blob: 53188c4cbf75b0a2f26b22d83f21269c3c565ef9 [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 */
Takashi Iwai1f0f4b82011-06-27 10:52:59 +0200351 hda_nid_t mixer_nid; /* analog-mixer NID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Takashi Iwai840b64c2010-07-13 22:49:01 +0200353 /* capture setup for dynamic dual-adc switch */
354 unsigned int cur_adc_idx;
355 hda_nid_t cur_adc;
356 unsigned int cur_adc_stream_tag;
357 unsigned int cur_adc_format;
358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200360 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 const struct hda_input_mux *input_mux;
362 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200363 struct alc_mic_route ext_mic;
Takashi Iwai8ed99d92011-05-17 12:05:02 +0200364 struct alc_mic_route dock_mic;
Takashi Iwai6c819492009-08-10 18:47:44 +0200365 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100368 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200370 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200371 int const_channel_count;
372 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373
374 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100375 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200376
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200377 /* dynamic controls, init_verbs and input_mux */
378 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100379 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200380 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200381 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200382 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200383 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
384 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100385
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100386 /* hooks */
387 void (*init_hook)(struct hda_codec *codec);
388 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100389#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500390 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100391#endif
Takashi Iwai1c716152011-04-07 10:37:16 +0200392 void (*shutup)(struct hda_codec *codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100393
Takashi Iwai834be882006-03-01 14:16:17 +0100394 /* for pin sensing */
Takashi Iwai834be882006-03-01 14:16:17 +0100395 unsigned int jack_present: 1;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200396 unsigned int line_jack_present:1;
Takashi Iwaie9427962011-04-28 15:46:07 +0200397 unsigned int master_mute:1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200398 unsigned int auto_mic:1;
Takashi Iwaid922b512011-04-28 12:18:53 +0200399 unsigned int automute:1; /* HP automute enabled */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200400 unsigned int detect_line:1; /* Line-out detection enabled */
401 unsigned int automute_lines:1; /* automute line-out as well */
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200402 unsigned int automute_hp_lo:1; /* both HP and LO available */
Takashi Iwaicb53c622007-08-10 17:21:45 +0200403
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100404 /* other flags */
405 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200406 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai584c0c42011-03-10 12:51:11 +0100407 unsigned int single_input_src:1;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +0200408 unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
Takashi Iwaid922b512011-04-28 12:18:53 +0200409
410 /* auto-mute control */
411 int automute_mode;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200412 hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
Takashi Iwaid922b512011-04-28 12:18:53 +0200413
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200414 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200415 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100416
Takashi Iwai2134ea42008-01-10 16:53:55 +0100417 /* for virtual master */
418 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200419#ifdef CONFIG_SND_HDA_POWER_SAVE
420 struct hda_loopback_check loopback;
421#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200422
423 /* for PLL fix */
424 hda_nid_t pll_nid;
425 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100426
427 /* fix-up list */
428 int fixup_id;
429 const struct alc_fixup *fixup_list;
430 const char *fixup_name;
Takashi Iwaice764ab2011-04-27 16:35:23 +0200431
432 /* multi-io */
433 int multi_ios;
434 struct alc_multi_io multi_io[4];
Kailang Yangdf694da2005-12-05 19:42:22 +0100435};
436
437/*
438 * configuration template - to be copied to the spec instance
439 */
440struct alc_config_preset {
Takashi Iwaia9111322011-05-02 11:30:18 +0200441 const struct snd_kcontrol_new *mixers[5]; /* should be identical size
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200442 * with spec
443 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200444 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100445 const struct hda_verb *init_verbs[5];
446 unsigned int num_dacs;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200447 const hda_nid_t *dac_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100448 hda_nid_t dig_out_nid; /* optional */
449 hda_nid_t hp_nid; /* optional */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200450 const hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100451 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200452 const hda_nid_t *adc_nids;
453 const hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100454 hda_nid_t dig_in_nid;
455 unsigned int num_channel_mode;
456 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200457 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200458 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200459 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100460 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100461 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200462 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100463 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200464#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +0200465 const struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500466 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200467#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468};
469
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
471/*
472 * input MUX handling
473 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200474static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
475 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476{
477 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
478 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200479 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
480 if (mux_idx >= spec->num_mux_defs)
481 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100482 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
483 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200484 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485}
486
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200487static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
488 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
490 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
491 struct alc_spec *spec = codec->spec;
492 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
493
494 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
495 return 0;
496}
497
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200498static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
502 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100503 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100505 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100506 hda_nid_t nid = spec->capsrc_nids ?
507 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200508 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Takashi Iwaicd896c32008-11-18 12:36:33 +0100510 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
511 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100512 if (!imux->num_items && mux_idx > 0)
513 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100514
Takashi Iwaia22d5432009-07-27 12:54:26 +0200515 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200516 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100517 /* Matrix-mixer style (e.g. ALC882) */
518 unsigned int *cur_val = &spec->cur_mux[adc_idx];
519 unsigned int i, idx;
520
521 idx = ucontrol->value.enumerated.item[0];
522 if (idx >= imux->num_items)
523 idx = imux->num_items - 1;
524 if (*cur_val == idx)
525 return 0;
526 for (i = 0; i < imux->num_items; i++) {
527 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
528 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
529 imux->items[i].index,
530 HDA_AMP_MUTE, v);
531 }
532 *cur_val = idx;
533 return 1;
534 } else {
535 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100536 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100537 &spec->cur_mux[adc_idx]);
538 }
539}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541/*
542 * channel mode setting
543 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200544static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
545 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546{
547 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
548 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100549 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
550 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551}
552
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200553static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
554 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555{
556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
557 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100558 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200559 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200560 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561}
562
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200563static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
564 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565{
566 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
567 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200568 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
569 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200570 &spec->ext_channel_count);
571 if (err >= 0 && !spec->const_channel_count) {
572 spec->multiout.max_channels = spec->ext_channel_count;
573 if (spec->need_dac_fix)
574 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
575 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200576 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577}
578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100580 * Control the mode of pin widget settings via the mixer. "pc" is used
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300581 * instead of "%" to avoid consequences of accidentally treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100582 * being part of a format specifier. Maximum allowed length of a value is
583 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100584 *
585 * Note: some retasking pin complexes seem to ignore requests for input
586 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
587 * are requested. Therefore order this list so that this behaviour will not
588 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200589 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
590 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200591 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200592static const char * const alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100593 "Mic 50pc bias", "Mic 80pc bias",
594 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100595};
Takashi Iwaia9111322011-05-02 11:30:18 +0200596static const unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100597 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100598};
599/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200600 * in the pin being assumed to be exclusively an input or an output pin. In
601 * addition, "input" pins may or may not process the mic bias option
602 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
603 * accept requests for bias as of chip versions up to March 2006) and/or
604 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100605 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200606#define ALC_PIN_DIR_IN 0x00
607#define ALC_PIN_DIR_OUT 0x01
608#define ALC_PIN_DIR_INOUT 0x02
609#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
610#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100611
Kailang Yangea1fb292008-08-26 12:58:38 +0200612/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100613 * For each direction the minimum and maximum values are given.
614 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200615static const signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100616 { 0, 2 }, /* ALC_PIN_DIR_IN */
617 { 3, 4 }, /* ALC_PIN_DIR_OUT */
618 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200619 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
620 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100621};
622#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
623#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
624#define alc_pin_mode_n_items(_dir) \
625 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
626
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200627static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
628 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200629{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100630 unsigned int item_num = uinfo->value.enumerated.item;
631 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
632
633 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200634 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100635 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
636
637 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
638 item_num = alc_pin_mode_min(dir);
639 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200640 return 0;
641}
642
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200643static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
644 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200645{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100646 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200647 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
648 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100649 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200650 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200651 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
652 AC_VERB_GET_PIN_WIDGET_CONTROL,
653 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200654
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100655 /* Find enumerated value for current pinctl setting */
656 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200657 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100658 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200659 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100660 return 0;
661}
662
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200663static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
664 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100665{
666 signed int change;
667 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
668 hda_nid_t nid = kcontrol->private_value & 0xffff;
669 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
670 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200671 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
672 AC_VERB_GET_PIN_WIDGET_CONTROL,
673 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100674
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200675 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100676 val = alc_pin_mode_min(dir);
677
678 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100679 if (change) {
680 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200681 snd_hda_codec_write_cache(codec, nid, 0,
682 AC_VERB_SET_PIN_WIDGET_CONTROL,
683 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100684
Kailang Yangea1fb292008-08-26 12:58:38 +0200685 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100686 * for the requested pin mode. Enum values of 2 or less are
687 * input modes.
688 *
689 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200690 * reduces noise slightly (particularly on input) so we'll
691 * do it. However, having both input and output buffers
692 * enabled simultaneously doesn't seem to be problematic if
693 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100694 */
695 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200696 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
697 HDA_AMP_MUTE, HDA_AMP_MUTE);
698 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
699 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100700 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200701 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
702 HDA_AMP_MUTE, HDA_AMP_MUTE);
703 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
704 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100705 }
706 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200707 return change;
708}
709
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100710#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200711 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100712 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100713 .info = alc_pin_mode_info, \
714 .get = alc_pin_mode_get, \
715 .put = alc_pin_mode_put, \
716 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100717
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100718/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
719 * together using a mask with more than one bit set. This control is
720 * currently used only by the ALC260 test model. At this stage they are not
721 * needed for any "production" models.
722 */
723#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200724#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200725
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200726static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
727 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100728{
729 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
730 hda_nid_t nid = kcontrol->private_value & 0xffff;
731 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
732 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200733 unsigned int val = snd_hda_codec_read(codec, nid, 0,
734 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100735
736 *valp = (val & mask) != 0;
737 return 0;
738}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200739static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
740 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100741{
742 signed int change;
743 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
744 hda_nid_t nid = kcontrol->private_value & 0xffff;
745 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
746 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200747 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
748 AC_VERB_GET_GPIO_DATA,
749 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100750
751 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200752 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
753 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100754 gpio_data &= ~mask;
755 else
756 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200757 snd_hda_codec_write_cache(codec, nid, 0,
758 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100759
760 return change;
761}
762#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
763 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100764 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100765 .info = alc_gpio_data_info, \
766 .get = alc_gpio_data_get, \
767 .put = alc_gpio_data_put, \
768 .private_value = nid | (mask<<16) }
769#endif /* CONFIG_SND_DEBUG */
770
Jonathan Woithe92621f12006-02-28 11:47:47 +0100771/* A switch control to allow the enabling of the digital IO pins on the
772 * ALC260. This is incredibly simplistic; the intention of this control is
773 * to provide something in the test model allowing digital outputs to be
774 * identified if present. If models are found which can utilise these
775 * outputs a more complete mixer control can be devised for those models if
776 * necessary.
777 */
778#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200779#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200780
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200781static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
782 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100783{
784 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
785 hda_nid_t nid = kcontrol->private_value & 0xffff;
786 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
787 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200788 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100789 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100790
791 *valp = (val & mask) != 0;
792 return 0;
793}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200794static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
795 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100796{
797 signed int change;
798 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
799 hda_nid_t nid = kcontrol->private_value & 0xffff;
800 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
801 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200802 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100803 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200804 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100805
806 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200807 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100808 if (val==0)
809 ctrl_data &= ~mask;
810 else
811 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200812 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
813 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100814
815 return change;
816}
817#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
818 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100819 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100820 .info = alc_spdif_ctrl_info, \
821 .get = alc_spdif_ctrl_get, \
822 .put = alc_spdif_ctrl_put, \
823 .private_value = nid | (mask<<16) }
824#endif /* CONFIG_SND_DEBUG */
825
Jonathan Woithef8225f62008-01-08 12:16:54 +0100826/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
827 * Again, this is only used in the ALC26x test models to help identify when
828 * the EAPD line must be asserted for features to work.
829 */
830#ifdef CONFIG_SND_DEBUG
831#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
832
833static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
834 struct snd_ctl_elem_value *ucontrol)
835{
836 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
837 hda_nid_t nid = kcontrol->private_value & 0xffff;
838 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
839 long *valp = ucontrol->value.integer.value;
840 unsigned int val = snd_hda_codec_read(codec, nid, 0,
841 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
842
843 *valp = (val & mask) != 0;
844 return 0;
845}
846
847static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
848 struct snd_ctl_elem_value *ucontrol)
849{
850 int change;
851 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
852 hda_nid_t nid = kcontrol->private_value & 0xffff;
853 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
854 long val = *ucontrol->value.integer.value;
855 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
856 AC_VERB_GET_EAPD_BTLENABLE,
857 0x00);
858
859 /* Set/unset the masked control bit(s) as needed */
860 change = (!val ? 0 : mask) != (ctrl_data & mask);
861 if (!val)
862 ctrl_data &= ~mask;
863 else
864 ctrl_data |= mask;
865 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
866 ctrl_data);
867
868 return change;
869}
870
871#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
872 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100873 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100874 .info = alc_eapd_ctrl_info, \
875 .get = alc_eapd_ctrl_get, \
876 .put = alc_eapd_ctrl_put, \
877 .private_value = nid | (mask<<16) }
878#endif /* CONFIG_SND_DEBUG */
879
Kailang Yangdf694da2005-12-05 19:42:22 +0100880/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100881 * set up the input pin config (depending on the given auto-pin type)
882 */
883static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
884 int auto_pin_type)
885{
886 unsigned int val = PIN_IN;
887
Takashi Iwai86e29592010-09-09 14:50:17 +0200888 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100889 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200890 unsigned int oldval;
891 oldval = snd_hda_codec_read(codec, nid, 0,
892 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100893 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100894 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200895 /* if the default pin setup is vref50, we give it priority */
896 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100897 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200898 else if (pincap & AC_PINCAP_VREF_50)
899 val = PIN_VREF50;
900 else if (pincap & AC_PINCAP_VREF_100)
901 val = PIN_VREF100;
902 else if (pincap & AC_PINCAP_VREF_GRD)
903 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100904 }
905 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
906}
907
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200908static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
909{
910 struct alc_spec *spec = codec->spec;
911 struct auto_pin_cfg *cfg = &spec->autocfg;
912
913 if (!cfg->line_outs) {
914 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
915 cfg->line_out_pins[cfg->line_outs])
916 cfg->line_outs++;
917 }
918 if (!cfg->speaker_outs) {
919 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
920 cfg->speaker_pins[cfg->speaker_outs])
921 cfg->speaker_outs++;
922 }
923 if (!cfg->hp_outs) {
924 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
925 cfg->hp_pins[cfg->hp_outs])
926 cfg->hp_outs++;
927 }
928}
929
Takashi Iwai23f0c042009-02-26 13:03:58 +0100930/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100931 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200932static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100933{
934 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
935 return;
936 spec->mixers[spec->num_mixers++] = mix;
937}
938
939static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
940{
941 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
942 return;
943 spec->init_verbs[spec->num_init_verbs++] = verb;
944}
945
946/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100947 * set up from the preset table
948 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200949static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200950 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100951{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200952 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100953 int i;
954
955 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100956 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100957 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200958 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
959 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100960 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200961
Kailang Yangdf694da2005-12-05 19:42:22 +0100962 spec->channel_mode = preset->channel_mode;
963 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200964 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200965 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100966
Hector Martin3b315d72009-06-02 10:54:19 +0200967 if (preset->const_channel_count)
968 spec->multiout.max_channels = preset->const_channel_count;
969 else
970 spec->multiout.max_channels = spec->channel_mode[0].channels;
971 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100972
973 spec->multiout.num_dacs = preset->num_dacs;
974 spec->multiout.dac_nids = preset->dac_nids;
975 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800976 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100977 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200978
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200979 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200980 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200981 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100982 spec->input_mux = preset->input_mux;
983
984 spec->num_adc_nids = preset->num_adc_nids;
985 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100986 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100987 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100988
989 spec->unsol_event = preset->unsol_event;
990 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200991#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100992 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200993 spec->loopback.amplist = preset->loopbacks;
994#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200995
996 if (preset->setup)
997 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200998
999 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01001000}
1001
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001002/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +02001003static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001004 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1005 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1006 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1007 { }
1008};
1009
Takashi Iwaia9111322011-05-02 11:30:18 +02001010static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001011 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1012 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1013 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
1014 { }
1015};
1016
Takashi Iwaia9111322011-05-02 11:30:18 +02001017static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02001018 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
1019 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
1020 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
1021 { }
1022};
1023
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001024/*
1025 * Fix hardware PLL issue
1026 * On some codecs, the analog PLL gating control must be off while
1027 * the default value is 1.
1028 */
1029static void alc_fix_pll(struct hda_codec *codec)
1030{
1031 struct alc_spec *spec = codec->spec;
1032 unsigned int val;
1033
1034 if (!spec->pll_nid)
1035 return;
1036 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1037 spec->pll_coef_idx);
1038 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1039 AC_VERB_GET_PROC_COEF, 0);
1040 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1041 spec->pll_coef_idx);
1042 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1043 val & ~(1 << spec->pll_coef_bit));
1044}
1045
1046static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1047 unsigned int coef_idx, unsigned int coef_bit)
1048{
1049 struct alc_spec *spec = codec->spec;
1050 spec->pll_nid = nid;
1051 spec->pll_coef_idx = coef_idx;
1052 spec->pll_coef_bit = coef_bit;
1053 alc_fix_pll(codec);
1054}
1055
Kailang Yang9ad0e492010-09-14 23:22:00 +02001056static int alc_init_jacks(struct hda_codec *codec)
1057{
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001058#ifdef CONFIG_SND_HDA_INPUT_JACK
Kailang Yang9ad0e492010-09-14 23:22:00 +02001059 struct alc_spec *spec = codec->spec;
1060 int err;
1061 unsigned int hp_nid = spec->autocfg.hp_pins[0];
1062 unsigned int mic_nid = spec->ext_mic.pin;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001063 unsigned int dock_nid = spec->dock_mic.pin;
Kailang Yang9ad0e492010-09-14 23:22:00 +02001064
Takashi Iwai265a0242010-09-21 11:26:21 +02001065 if (hp_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001066 err = snd_hda_input_jack_add(codec, hp_nid,
1067 SND_JACK_HEADPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001068 if (err < 0)
1069 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001070 snd_hda_input_jack_report(codec, hp_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001071 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001072
Takashi Iwai265a0242010-09-21 11:26:21 +02001073 if (mic_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001074 err = snd_hda_input_jack_add(codec, mic_nid,
1075 SND_JACK_MICROPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001076 if (err < 0)
1077 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001078 snd_hda_input_jack_report(codec, mic_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001079 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001080 if (dock_nid) {
1081 err = snd_hda_input_jack_add(codec, dock_nid,
1082 SND_JACK_MICROPHONE, NULL);
1083 if (err < 0)
1084 return err;
1085 snd_hda_input_jack_report(codec, dock_nid);
1086 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001087#endif /* CONFIG_SND_HDA_INPUT_JACK */
Kailang Yang9ad0e492010-09-14 23:22:00 +02001088 return 0;
1089}
Kailang Yang9ad0e492010-09-14 23:22:00 +02001090
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001091static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +02001092{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001093 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +02001094
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001095 for (i = 0; i < num_pins; i++) {
1096 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001097 if (!nid)
1098 break;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001099 snd_hda_input_jack_report(codec, nid);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001100 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001101 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001102 return present;
1103}
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001104
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001105static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +02001106 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001107{
1108 struct alc_spec *spec = codec->spec;
1109 unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02001110 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001111 int i;
1112
1113 for (i = 0; i < num_pins; i++) {
1114 hda_nid_t nid = pins[i];
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001115 if (!nid)
1116 break;
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001117 switch (spec->automute_mode) {
1118 case ALC_AUTOMUTE_PIN:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001119 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001120 AC_VERB_SET_PIN_WIDGET_CONTROL,
1121 pin_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001122 break;
1123 case ALC_AUTOMUTE_AMP:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001124 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001125 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001126 break;
1127 case ALC_AUTOMUTE_MIXER:
1128 nid = spec->automute_mixer_nid[i];
1129 if (!nid)
1130 break;
1131 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001132 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001133 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001134 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001135 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001136 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001137 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001138}
1139
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001140/* Toggle internal speakers muting */
1141static void update_speakers(struct hda_codec *codec)
1142{
1143 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001144 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001145
Takashi Iwaic0a20262011-06-10 15:28:15 +02001146 /* Control HP pins/amps depending on master_mute state;
1147 * in general, HP pins/amps control should be enabled in all cases,
1148 * but currently set only for master_mute, just to be safe
1149 */
1150 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1151 spec->autocfg.hp_pins, spec->master_mute, true);
1152
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001153 if (!spec->automute)
1154 on = 0;
1155 else
1156 on = spec->jack_present | spec->line_jack_present;
1157 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001158 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001159 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001160
1161 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001162 /* if LO is a copy of either HP or Speaker, don't need to handle it */
1163 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
1164 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001165 return;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001166 if (!spec->automute_lines || !spec->automute)
1167 on = 0;
1168 else
1169 on = spec->jack_present;
1170 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001171 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001172 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001173}
1174
1175static void alc_hp_automute(struct hda_codec *codec)
1176{
1177 struct alc_spec *spec = codec->spec;
1178
1179 if (!spec->automute)
1180 return;
1181 spec->jack_present =
1182 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1183 spec->autocfg.hp_pins);
1184 update_speakers(codec);
1185}
1186
1187static void alc_line_automute(struct hda_codec *codec)
1188{
1189 struct alc_spec *spec = codec->spec;
1190
1191 if (!spec->automute || !spec->detect_line)
1192 return;
1193 spec->line_jack_present =
1194 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
1195 spec->autocfg.line_out_pins);
1196 update_speakers(codec);
1197}
1198
Takashi Iwai8d087c72011-06-28 12:45:47 +02001199#define get_connection_index(codec, mux, nid) \
1200 snd_hda_get_conn_index(codec, mux, nid, 0)
Takashi Iwai6c819492009-08-10 18:47:44 +02001201
Takashi Iwai840b64c2010-07-13 22:49:01 +02001202/* switch the current ADC according to the jack state */
1203static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1204{
1205 struct alc_spec *spec = codec->spec;
1206 unsigned int present;
1207 hda_nid_t new_adc;
1208
1209 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1210 if (present)
1211 spec->cur_adc_idx = 1;
1212 else
1213 spec->cur_adc_idx = 0;
1214 new_adc = spec->adc_nids[spec->cur_adc_idx];
1215 if (spec->cur_adc && spec->cur_adc != new_adc) {
1216 /* stream is running, let's swap the current ADC */
Takashi Iwaif0cea792010-08-13 11:56:53 +02001217 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai840b64c2010-07-13 22:49:01 +02001218 spec->cur_adc = new_adc;
1219 snd_hda_codec_setup_stream(codec, new_adc,
1220 spec->cur_adc_stream_tag, 0,
1221 spec->cur_adc_format);
1222 }
1223}
1224
Kailang Yang7fb0d782008-10-15 11:12:35 +02001225static void alc_mic_automute(struct hda_codec *codec)
1226{
1227 struct alc_spec *spec = codec->spec;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001228 struct alc_mic_route *dead1, *dead2, *alive;
Takashi Iwai6c819492009-08-10 18:47:44 +02001229 unsigned int present, type;
1230 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001231
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001232 if (!spec->auto_mic)
1233 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001234 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1235 return;
1236 if (snd_BUG_ON(!spec->adc_nids))
1237 return;
1238
Takashi Iwai840b64c2010-07-13 22:49:01 +02001239 if (spec->dual_adc_switch) {
1240 alc_dual_mic_adc_auto_switch(codec);
1241 return;
1242 }
1243
Takashi Iwai6c819492009-08-10 18:47:44 +02001244 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1245
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001246 alive = &spec->int_mic;
1247 dead1 = &spec->ext_mic;
1248 dead2 = &spec->dock_mic;
1249
Wu Fengguang864f92b2009-11-18 12:38:02 +08001250 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001251 if (present) {
1252 alive = &spec->ext_mic;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001253 dead1 = &spec->int_mic;
1254 dead2 = &spec->dock_mic;
1255 }
1256 if (!present && spec->dock_mic.pin > 0) {
1257 present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
1258 if (present) {
1259 alive = &spec->dock_mic;
1260 dead1 = &spec->int_mic;
1261 dead2 = &spec->ext_mic;
1262 }
1263 snd_hda_input_jack_report(codec, spec->dock_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001264 }
1265
Takashi Iwai6c819492009-08-10 18:47:44 +02001266 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1267 if (type == AC_WID_AUD_MIX) {
1268 /* Matrix-mixer style (e.g. ALC882) */
1269 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1270 alive->mux_idx,
1271 HDA_AMP_MUTE, 0);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001272 if (dead1->pin > 0)
1273 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1274 dead1->mux_idx,
1275 HDA_AMP_MUTE, HDA_AMP_MUTE);
1276 if (dead2->pin > 0)
1277 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1278 dead2->mux_idx,
1279 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai6c819492009-08-10 18:47:44 +02001280 } else {
1281 /* MUX style (e.g. ALC880) */
1282 snd_hda_codec_write_cache(codec, cap_nid, 0,
1283 AC_VERB_SET_CONNECT_SEL,
1284 alive->mux_idx);
1285 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001286 snd_hda_input_jack_report(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001287
1288 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001289}
1290
Kailang Yangc9b58002007-10-16 14:30:01 +02001291/* unsolicited event for HP jack sensing */
1292static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1293{
1294 if (codec->vendor_id == 0x10ec0880)
1295 res >>= 28;
1296 else
1297 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001298 switch (res) {
1299 case ALC880_HP_EVENT:
Takashi Iwaid922b512011-04-28 12:18:53 +02001300 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001301 break;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001302 case ALC880_FRONT_EVENT:
1303 alc_line_automute(codec);
1304 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001305 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001306 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001307 break;
1308 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001309}
1310
1311static void alc_inithook(struct hda_codec *codec)
1312{
Takashi Iwaid922b512011-04-28 12:18:53 +02001313 alc_hp_automute(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001314 alc_line_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001315 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001316}
1317
Kailang Yangf9423e72008-05-27 12:32:25 +02001318/* additional initialization for ALC888 variants */
1319static void alc888_coef_init(struct hda_codec *codec)
1320{
1321 unsigned int tmp;
1322
1323 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1324 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1325 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001326 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001327 /* alc888S-VC */
1328 snd_hda_codec_read(codec, 0x20, 0,
1329 AC_VERB_SET_PROC_COEF, 0x830);
1330 else
1331 /* alc888-VB */
1332 snd_hda_codec_read(codec, 0x20, 0,
1333 AC_VERB_SET_PROC_COEF, 0x3030);
1334}
1335
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001336static void alc889_coef_init(struct hda_codec *codec)
1337{
1338 unsigned int tmp;
1339
1340 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1341 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1342 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1343 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1344}
1345
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001346/* turn on/off EAPD control (only if available) */
1347static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1348{
1349 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1350 return;
1351 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1352 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1353 on ? 2 : 0);
1354}
1355
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001356/* turn on/off EAPD controls of the codec */
1357static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
1358{
1359 /* We currently only handle front, HP */
Takashi Iwai39fa84e2011-06-27 15:28:57 +02001360 static hda_nid_t pins[] = {
1361 0x0f, 0x10, 0x14, 0x15, 0
1362 };
1363 hda_nid_t *p;
1364 for (p = pins; *p; p++)
1365 set_eapd(codec, *p, on);
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001366}
1367
Takashi Iwai1c716152011-04-07 10:37:16 +02001368/* generic shutup callback;
1369 * just turning off EPAD and a little pause for avoiding pop-noise
1370 */
1371static void alc_eapd_shutup(struct hda_codec *codec)
1372{
1373 alc_auto_setup_eapd(codec, false);
1374 msleep(200);
1375}
1376
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001377static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001378{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001379 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001380
Takashi Iwai39fa84e2011-06-27 15:28:57 +02001381 alc_auto_setup_eapd(codec, true);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001382 switch (type) {
1383 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001384 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1385 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001386 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001387 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1388 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001389 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001390 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1391 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001392 case ALC_INIT_DEFAULT:
Kailang Yangc9b58002007-10-16 14:30:01 +02001393 switch (codec->vendor_id) {
1394 case 0x10ec0260:
1395 snd_hda_codec_write(codec, 0x1a, 0,
1396 AC_VERB_SET_COEF_INDEX, 7);
1397 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1398 AC_VERB_GET_PROC_COEF, 0);
1399 snd_hda_codec_write(codec, 0x1a, 0,
1400 AC_VERB_SET_COEF_INDEX, 7);
1401 snd_hda_codec_write(codec, 0x1a, 0,
1402 AC_VERB_SET_PROC_COEF,
1403 tmp | 0x2010);
1404 break;
1405 case 0x10ec0262:
1406 case 0x10ec0880:
1407 case 0x10ec0882:
1408 case 0x10ec0883:
1409 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001410 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +01001411 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001412 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001413 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001414 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001415 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001416 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001417#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001418 case 0x10ec0267:
1419 case 0x10ec0268:
1420 snd_hda_codec_write(codec, 0x20, 0,
1421 AC_VERB_SET_COEF_INDEX, 7);
1422 tmp = snd_hda_codec_read(codec, 0x20, 0,
1423 AC_VERB_GET_PROC_COEF, 0);
1424 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001425 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001426 snd_hda_codec_write(codec, 0x20, 0,
1427 AC_VERB_SET_PROC_COEF,
1428 tmp | 0x3000);
1429 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001430#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001431 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001432 break;
1433 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001434}
Kailang Yangea1fb292008-08-26 12:58:38 +02001435
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001436static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
1437 struct snd_ctl_elem_info *uinfo)
1438{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001439 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1440 struct alc_spec *spec = codec->spec;
1441 static const char * const texts2[] = {
1442 "Disabled", "Enabled"
1443 };
1444 static const char * const texts3[] = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001445 "Disabled", "Speaker Only", "Line-Out+Speaker"
1446 };
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001447 const char * const *texts;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001448
1449 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1450 uinfo->count = 1;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001451 if (spec->automute_hp_lo) {
1452 uinfo->value.enumerated.items = 3;
1453 texts = texts3;
1454 } else {
1455 uinfo->value.enumerated.items = 2;
1456 texts = texts2;
1457 }
1458 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1459 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001460 strcpy(uinfo->value.enumerated.name,
1461 texts[uinfo->value.enumerated.item]);
1462 return 0;
1463}
1464
1465static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
1466 struct snd_ctl_elem_value *ucontrol)
1467{
1468 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1469 struct alc_spec *spec = codec->spec;
1470 unsigned int val;
1471 if (!spec->automute)
1472 val = 0;
1473 else if (!spec->automute_lines)
1474 val = 1;
1475 else
1476 val = 2;
1477 ucontrol->value.enumerated.item[0] = val;
1478 return 0;
1479}
1480
1481static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
1482 struct snd_ctl_elem_value *ucontrol)
1483{
1484 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1485 struct alc_spec *spec = codec->spec;
1486
1487 switch (ucontrol->value.enumerated.item[0]) {
1488 case 0:
1489 if (!spec->automute)
1490 return 0;
1491 spec->automute = 0;
1492 break;
1493 case 1:
1494 if (spec->automute && !spec->automute_lines)
1495 return 0;
1496 spec->automute = 1;
1497 spec->automute_lines = 0;
1498 break;
1499 case 2:
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001500 if (!spec->automute_hp_lo)
1501 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001502 if (spec->automute && spec->automute_lines)
1503 return 0;
1504 spec->automute = 1;
1505 spec->automute_lines = 1;
1506 break;
1507 default:
1508 return -EINVAL;
1509 }
1510 update_speakers(codec);
1511 return 1;
1512}
1513
Takashi Iwaia9111322011-05-02 11:30:18 +02001514static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001515 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1516 .name = "Auto-Mute Mode",
1517 .info = alc_automute_mode_info,
1518 .get = alc_automute_mode_get,
1519 .put = alc_automute_mode_put,
1520};
1521
1522static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
1523
1524static int alc_add_automute_mode_enum(struct hda_codec *codec)
1525{
1526 struct alc_spec *spec = codec->spec;
1527 struct snd_kcontrol_new *knew;
1528
1529 knew = alc_kcontrol_new(spec);
1530 if (!knew)
1531 return -ENOMEM;
1532 *knew = alc_automute_mode_enum;
1533 knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
1534 if (!knew->name)
1535 return -ENOMEM;
1536 return 0;
1537}
1538
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001539static void alc_init_auto_hp(struct hda_codec *codec)
1540{
1541 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001542 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001543 int present = 0;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001544 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001545
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001546 if (cfg->hp_pins[0])
1547 present++;
1548 if (cfg->line_out_pins[0])
1549 present++;
1550 if (cfg->speaker_pins[0])
1551 present++;
1552 if (present < 2) /* need two different output types */
1553 return;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001554 if (present == 3)
1555 spec->automute_hp_lo = 1; /* both HP and LO automute */
Kailang Yangc9b58002007-10-16 14:30:01 +02001556
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001557 if (!cfg->speaker_pins[0]) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001558 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1559 sizeof(cfg->speaker_pins));
1560 cfg->speaker_outs = cfg->line_outs;
1561 }
1562
1563 if (!cfg->hp_pins[0]) {
1564 memcpy(cfg->hp_pins, cfg->line_out_pins,
1565 sizeof(cfg->hp_pins));
1566 cfg->hp_outs = cfg->line_outs;
1567 }
1568
1569 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001570 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001571 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001572 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001573 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001574 nid);
1575 snd_hda_codec_write_cache(codec, nid, 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001576 AC_VERB_SET_UNSOLICITED_ENABLE,
1577 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaid922b512011-04-28 12:18:53 +02001578 spec->automute = 1;
1579 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001580 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001581 if (spec->automute && cfg->line_out_pins[0] &&
1582 cfg->line_out_pins[0] != cfg->hp_pins[0] &&
1583 cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
1584 for (i = 0; i < cfg->line_outs; i++) {
1585 hda_nid_t nid = cfg->line_out_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001586 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001587 continue;
1588 snd_printdd("realtek: Enable Line-Out auto-muting "
1589 "on NID 0x%x\n", nid);
1590 snd_hda_codec_write_cache(codec, nid, 0,
1591 AC_VERB_SET_UNSOLICITED_ENABLE,
1592 AC_USRSP_EN | ALC880_FRONT_EVENT);
1593 spec->detect_line = 1;
1594 }
Takashi Iwai52d3cb82011-05-17 10:04:08 +02001595 spec->automute_lines = spec->detect_line;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001596 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001597
1598 if (spec->automute) {
1599 /* create a control for automute mode */
1600 alc_add_automute_mode_enum(codec);
1601 spec->unsol_event = alc_sku_unsol_event;
1602 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001603}
1604
Takashi Iwai6c819492009-08-10 18:47:44 +02001605static void alc_init_auto_mic(struct hda_codec *codec)
1606{
1607 struct alc_spec *spec = codec->spec;
1608 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001609 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001610 int i;
1611
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001612 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001613 for (i = 0; i < cfg->num_inputs; i++) {
1614 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001615 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001616 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001617 switch (snd_hda_get_input_pin_attr(defcfg)) {
1618 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001619 if (fixed)
1620 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001621 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1622 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001623 fixed = nid;
1624 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001625 case INPUT_PIN_ATTR_UNUSED:
1626 return; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001627 case INPUT_PIN_ATTR_DOCK:
1628 if (dock)
1629 return; /* already occupied */
1630 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
1631 return; /* invalid type */
1632 dock = nid;
1633 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001634 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001635 if (ext)
1636 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001637 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1638 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001639 ext = nid;
1640 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001641 }
1642 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001643 if (!ext && dock) {
1644 ext = dock;
1645 dock = 0;
1646 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001647 if (!ext || !fixed)
1648 return;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001649 if (!is_jack_detectable(codec, ext))
Takashi Iwai6c819492009-08-10 18:47:44 +02001650 return; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001651 if (dock && !is_jack_detectable(codec, dock))
1652 return; /* no unsol support */
1653 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1654 ext, fixed, dock);
Takashi Iwai6c819492009-08-10 18:47:44 +02001655 spec->ext_mic.pin = ext;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001656 spec->dock_mic.pin = dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001657 spec->int_mic.pin = fixed;
1658 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001659 spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai6c819492009-08-10 18:47:44 +02001660 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1661 spec->auto_mic = 1;
1662 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1663 AC_VERB_SET_UNSOLICITED_ENABLE,
1664 AC_USRSP_EN | ALC880_MIC_EVENT);
1665 spec->unsol_event = alc_sku_unsol_event;
1666}
1667
David Henningsson90622912010-10-14 14:50:18 +02001668/* Could be any non-zero and even value. When used as fixup, tells
1669 * the driver to ignore any present sku defines.
1670 */
1671#define ALC_FIXUP_SKU_IGNORE (2)
1672
Kailang Yangda00c242010-03-19 11:23:45 +01001673static int alc_auto_parse_customize_define(struct hda_codec *codec)
1674{
1675 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001676 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001677 struct alc_spec *spec = codec->spec;
1678
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001679 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1680
David Henningsson90622912010-10-14 14:50:18 +02001681 if (spec->cdefine.fixup) {
1682 ass = spec->cdefine.sku_cfg;
1683 if (ass == ALC_FIXUP_SKU_IGNORE)
1684 return -1;
1685 goto do_sku;
1686 }
1687
Kailang Yangda00c242010-03-19 11:23:45 +01001688 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001689 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001690 goto do_sku;
1691
1692 nid = 0x1d;
1693 if (codec->vendor_id == 0x10ec0260)
1694 nid = 0x17;
1695 ass = snd_hda_codec_get_pincfg(codec, nid);
1696
1697 if (!(ass & 1)) {
1698 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1699 codec->chip_name, ass);
1700 return -1;
1701 }
1702
1703 /* check sum */
1704 tmp = 0;
1705 for (i = 1; i < 16; i++) {
1706 if ((ass >> i) & 1)
1707 tmp++;
1708 }
1709 if (((ass >> 16) & 0xf) != tmp)
1710 return -1;
1711
1712 spec->cdefine.port_connectivity = ass >> 30;
1713 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1714 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1715 spec->cdefine.customization = ass >> 8;
1716do_sku:
1717 spec->cdefine.sku_cfg = ass;
1718 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1719 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1720 spec->cdefine.swap = (ass & 0x2) >> 1;
1721 spec->cdefine.override = ass & 0x1;
1722
1723 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1724 nid, spec->cdefine.sku_cfg);
1725 snd_printd("SKU: port_connectivity=0x%x\n",
1726 spec->cdefine.port_connectivity);
1727 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1728 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1729 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1730 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1731 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1732 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1733 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1734
1735 return 0;
1736}
1737
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001738static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1739{
1740 int i;
1741 for (i = 0; i < nums; i++)
1742 if (list[i] == nid)
1743 return true;
1744 return false;
1745}
1746
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001747/* check subsystem ID and set up device-specific initialization;
1748 * return 1 if initialized, 0 if invalid SSID
1749 */
1750/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1751 * 31 ~ 16 : Manufacture ID
1752 * 15 ~ 8 : SKU ID
1753 * 7 ~ 0 : Assembly ID
1754 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1755 */
1756static int alc_subsystem_id(struct hda_codec *codec,
1757 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001758 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001759{
1760 unsigned int ass, tmp, i;
1761 unsigned nid;
1762 struct alc_spec *spec = codec->spec;
1763
David Henningsson90622912010-10-14 14:50:18 +02001764 if (spec->cdefine.fixup) {
1765 ass = spec->cdefine.sku_cfg;
1766 if (ass == ALC_FIXUP_SKU_IGNORE)
1767 return 0;
1768 goto do_sku;
1769 }
1770
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001771 ass = codec->subsystem_id & 0xffff;
1772 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1773 goto do_sku;
1774
1775 /* invalid SSID, check the special NID pin defcfg instead */
1776 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001777 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001778 * 29~21 : reserve
1779 * 20 : PCBEEP input
1780 * 19~16 : Check sum (15:1)
1781 * 15~1 : Custom
1782 * 0 : override
1783 */
1784 nid = 0x1d;
1785 if (codec->vendor_id == 0x10ec0260)
1786 nid = 0x17;
1787 ass = snd_hda_codec_get_pincfg(codec, nid);
1788 snd_printd("realtek: No valid SSID, "
1789 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001790 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001791 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001792 return 0;
1793 if ((ass >> 30) != 1) /* no physical connection */
1794 return 0;
1795
1796 /* check sum */
1797 tmp = 0;
1798 for (i = 1; i < 16; i++) {
1799 if ((ass >> i) & 1)
1800 tmp++;
1801 }
1802 if (((ass >> 16) & 0xf) != tmp)
1803 return 0;
1804do_sku:
1805 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1806 ass & 0xffff, codec->vendor_id);
1807 /*
1808 * 0 : override
1809 * 1 : Swap Jack
1810 * 2 : 0 --> Desktop, 1 --> Laptop
1811 * 3~5 : External Amplifier control
1812 * 7~6 : Reserved
1813 */
1814 tmp = (ass & 0x38) >> 3; /* external Amp control */
1815 switch (tmp) {
1816 case 1:
1817 spec->init_amp = ALC_INIT_GPIO1;
1818 break;
1819 case 3:
1820 spec->init_amp = ALC_INIT_GPIO2;
1821 break;
1822 case 7:
1823 spec->init_amp = ALC_INIT_GPIO3;
1824 break;
1825 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001826 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001827 spec->init_amp = ALC_INIT_DEFAULT;
1828 break;
1829 }
1830
1831 /* is laptop or Desktop and enable the function "Mute internal speaker
1832 * when the external headphone out jack is plugged"
1833 */
1834 if (!(ass & 0x8000))
1835 return 1;
1836 /*
1837 * 10~8 : Jack location
1838 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1839 * 14~13: Resvered
1840 * 15 : 1 --> enable the function "Mute internal speaker
1841 * when the external headphone out jack is plugged"
1842 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001843 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001844 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001845 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1846 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001847 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001848 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001849 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001850 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001851 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001852 else if (tmp == 3)
1853 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001854 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001855 return 1;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001856 if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
1857 spec->autocfg.line_outs))
1858 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001859 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001860 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001861 return 1;
1862}
Kailang Yangea1fb292008-08-26 12:58:38 +02001863
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001864static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001865 hda_nid_t porta, hda_nid_t porte,
1866 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001867{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001868 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001869 struct alc_spec *spec = codec->spec;
1870 snd_printd("realtek: "
1871 "Enable default setup for auto mode as fallback\n");
1872 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001873 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001874
1875 alc_init_auto_hp(codec);
1876 alc_init_auto_mic(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001877}
1878
Takashi Iwai41e41f12005-06-08 14:48:49 +02001879/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001880 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001881 */
1882
1883struct alc_pincfg {
1884 hda_nid_t nid;
1885 u32 val;
1886};
1887
Todd Broche1eb5f12010-12-06 11:19:51 -08001888struct alc_model_fixup {
1889 const int id;
1890 const char *name;
1891};
1892
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001893struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001894 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001895 bool chained;
1896 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001897 union {
1898 unsigned int sku;
1899 const struct alc_pincfg *pins;
1900 const struct hda_verb *verbs;
1901 void (*func)(struct hda_codec *codec,
1902 const struct alc_fixup *fix,
1903 int action);
1904 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001905};
1906
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001907enum {
1908 ALC_FIXUP_INVALID,
1909 ALC_FIXUP_SKU,
1910 ALC_FIXUP_PINS,
1911 ALC_FIXUP_VERBS,
1912 ALC_FIXUP_FUNC,
1913};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001914
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001915enum {
1916 ALC_FIXUP_ACT_PRE_PROBE,
1917 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001918 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001919};
1920
1921static void alc_apply_fixup(struct hda_codec *codec, int action)
1922{
1923 struct alc_spec *spec = codec->spec;
1924 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001925#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001926 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001927#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001928 int depth = 0;
1929
1930 if (!spec->fixup_list)
1931 return;
1932
1933 while (id >= 0) {
1934 const struct alc_fixup *fix = spec->fixup_list + id;
1935 const struct alc_pincfg *cfg;
1936
1937 switch (fix->type) {
1938 case ALC_FIXUP_SKU:
1939 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
1940 break;;
1941 snd_printdd(KERN_INFO "hda_codec: %s: "
1942 "Apply sku override for %s\n",
1943 codec->chip_name, modelname);
1944 spec->cdefine.sku_cfg = fix->v.sku;
1945 spec->cdefine.fixup = 1;
1946 break;
1947 case ALC_FIXUP_PINS:
1948 cfg = fix->v.pins;
1949 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1950 break;
1951 snd_printdd(KERN_INFO "hda_codec: %s: "
1952 "Apply pincfg for %s\n",
1953 codec->chip_name, modelname);
1954 for (; cfg->nid; cfg++)
1955 snd_hda_codec_set_pincfg(codec, cfg->nid,
1956 cfg->val);
1957 break;
1958 case ALC_FIXUP_VERBS:
1959 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
1960 break;
1961 snd_printdd(KERN_INFO "hda_codec: %s: "
1962 "Apply fix-verbs for %s\n",
1963 codec->chip_name, modelname);
1964 add_verb(codec->spec, fix->v.verbs);
1965 break;
1966 case ALC_FIXUP_FUNC:
1967 if (!fix->v.func)
1968 break;
1969 snd_printdd(KERN_INFO "hda_codec: %s: "
1970 "Apply fix-func for %s\n",
1971 codec->chip_name, modelname);
1972 fix->v.func(codec, fix, action);
1973 break;
1974 default:
1975 snd_printk(KERN_ERR "hda_codec: %s: "
1976 "Invalid fixup type %d\n",
1977 codec->chip_name, fix->type);
1978 break;
1979 }
Takashi Iwai24af2b12011-05-02 13:55:36 +02001980 if (!fix->chained)
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001981 break;
1982 if (++depth > 10)
1983 break;
Takashi Iwai24af2b12011-05-02 13:55:36 +02001984 id = fix->chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01001985 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001986}
1987
Todd Broche1eb5f12010-12-06 11:19:51 -08001988static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001989 const struct alc_model_fixup *models,
1990 const struct snd_pci_quirk *quirk,
1991 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08001992{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001993 struct alc_spec *spec = codec->spec;
1994 int id = -1;
1995 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08001996
Todd Broche1eb5f12010-12-06 11:19:51 -08001997 if (codec->modelname && models) {
1998 while (models->name) {
1999 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002000 id = models->id;
2001 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002002 break;
2003 }
2004 models++;
2005 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002006 }
2007 if (id < 0) {
2008 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
2009 if (quirk) {
2010 id = quirk->value;
2011#ifdef CONFIG_SND_DEBUG_VERBOSE
2012 name = quirk->name;
2013#endif
2014 }
2015 }
2016
2017 spec->fixup_id = id;
2018 if (id >= 0) {
2019 spec->fixup_list = fixlist;
2020 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002021 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002022}
2023
Kailang Yang274693f2009-12-03 10:07:50 +01002024static int alc_read_coef_idx(struct hda_codec *codec,
2025 unsigned int coef_idx)
2026{
2027 unsigned int val;
2028 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2029 coef_idx);
2030 val = snd_hda_codec_read(codec, 0x20, 0,
2031 AC_VERB_GET_PROC_COEF, 0);
2032 return val;
2033}
2034
Kailang Yang977ddd62010-09-15 10:02:29 +02002035static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
2036 unsigned int coef_val)
2037{
2038 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2039 coef_idx);
2040 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
2041 coef_val);
2042}
2043
Takashi Iwai757899a2010-07-30 10:48:14 +02002044/* set right pin controls for digital I/O */
2045static void alc_auto_init_digital(struct hda_codec *codec)
2046{
2047 struct alc_spec *spec = codec->spec;
2048 int i;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002049 hda_nid_t pin, dac;
Takashi Iwai757899a2010-07-30 10:48:14 +02002050
2051 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2052 pin = spec->autocfg.dig_out_pins[i];
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002053 if (!pin)
2054 continue;
2055 snd_hda_codec_write(codec, pin, 0,
2056 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
2057 if (!i)
2058 dac = spec->multiout.dig_out_nid;
2059 else
2060 dac = spec->slave_dig_outs[i - 1];
2061 if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
2062 continue;
2063 snd_hda_codec_write(codec, dac, 0,
2064 AC_VERB_SET_AMP_GAIN_MUTE,
2065 AMP_OUT_UNMUTE);
Takashi Iwai757899a2010-07-30 10:48:14 +02002066 }
2067 pin = spec->autocfg.dig_in_pin;
2068 if (pin)
2069 snd_hda_codec_write(codec, pin, 0,
2070 AC_VERB_SET_PIN_WIDGET_CONTROL,
2071 PIN_IN);
2072}
2073
2074/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
2075static void alc_auto_parse_digital(struct hda_codec *codec)
2076{
2077 struct alc_spec *spec = codec->spec;
2078 int i, err;
2079 hda_nid_t dig_nid;
2080
2081 /* support multiple SPDIFs; the secondary is set up as a slave */
2082 for (i = 0; i < spec->autocfg.dig_outs; i++) {
Takashi Iwaia9267572011-07-07 15:12:55 +02002083 hda_nid_t conn[4];
Takashi Iwai757899a2010-07-30 10:48:14 +02002084 err = snd_hda_get_connections(codec,
2085 spec->autocfg.dig_out_pins[i],
Takashi Iwaia9267572011-07-07 15:12:55 +02002086 conn, ARRAY_SIZE(conn));
Takashi Iwai757899a2010-07-30 10:48:14 +02002087 if (err < 0)
2088 continue;
Takashi Iwaia9267572011-07-07 15:12:55 +02002089 dig_nid = conn[0]; /* assume the first element is audio-out */
Takashi Iwai757899a2010-07-30 10:48:14 +02002090 if (!i) {
2091 spec->multiout.dig_out_nid = dig_nid;
2092 spec->dig_out_type = spec->autocfg.dig_out_type[0];
2093 } else {
2094 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
2095 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
2096 break;
2097 spec->slave_dig_outs[i - 1] = dig_nid;
2098 }
2099 }
2100
2101 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02002102 dig_nid = codec->start_nid;
2103 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
2104 unsigned int wcaps = get_wcaps(codec, dig_nid);
2105 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
2106 continue;
2107 if (!(wcaps & AC_WCAP_DIGITAL))
2108 continue;
2109 if (!(wcaps & AC_WCAP_CONN_LIST))
2110 continue;
2111 err = get_connection_index(codec, dig_nid,
2112 spec->autocfg.dig_in_pin);
2113 if (err >= 0) {
2114 spec->dig_in_nid = dig_nid;
2115 break;
2116 }
2117 }
Takashi Iwai757899a2010-07-30 10:48:14 +02002118 }
2119}
2120
Takashi Iwaif95474e2007-07-10 00:47:43 +02002121/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002122 * ALC888
2123 */
2124
2125/*
2126 * 2ch mode
2127 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002128static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002129/* Mic-in jack as mic in */
2130 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2131 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2132/* Line-in jack as Line in */
2133 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2134 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2135/* Line-Out as Front */
2136 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2137 { } /* end */
2138};
2139
2140/*
2141 * 4ch mode
2142 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002143static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002144/* Mic-in jack as mic in */
2145 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2146 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2147/* Line-in jack as Surround */
2148 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2149 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2150/* Line-Out as Front */
2151 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2152 { } /* end */
2153};
2154
2155/*
2156 * 6ch mode
2157 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002158static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002159/* Mic-in jack as CLFE */
2160 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2161 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2162/* Line-in jack as Surround */
2163 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2164 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2165/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
2166 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2167 { } /* end */
2168};
2169
2170/*
2171 * 8ch mode
2172 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002173static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002174/* Mic-in jack as CLFE */
2175 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2176 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2177/* Line-in jack as Surround */
2178 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2179 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2180/* Line-Out as Side */
2181 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2182 { } /* end */
2183};
2184
Takashi Iwaia9111322011-05-02 11:30:18 +02002185static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002186 { 2, alc888_4ST_ch2_intel_init },
2187 { 4, alc888_4ST_ch4_intel_init },
2188 { 6, alc888_4ST_ch6_intel_init },
2189 { 8, alc888_4ST_ch8_intel_init },
2190};
2191
2192/*
2193 * ALC888 Fujitsu Siemens Amillo xa3530
2194 */
2195
Takashi Iwaia9111322011-05-02 11:30:18 +02002196static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002197/* Front Mic: set to PIN_IN (empty by default) */
2198 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2199/* Connect Internal HP to Front */
2200 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2201 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2202 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2203/* Connect Bass HP to Front */
2204 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2205 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2206 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2207/* Connect Line-Out side jack (SPDIF) to Side */
2208 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2209 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2210 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2211/* Connect Mic jack to CLFE */
2212 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2213 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2214 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
2215/* Connect Line-in jack to Surround */
2216 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2217 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2218 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
2219/* Connect HP out jack to Front */
2220 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2221 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2222 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2223/* Enable unsolicited event for HP jack and Line-out jack */
2224 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2225 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2226 {}
2227};
2228
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002229static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02002230{
2231 struct alc_spec *spec = codec->spec;
2232
2233 spec->autocfg.hp_pins[0] = 0x15;
2234 spec->autocfg.speaker_pins[0] = 0x14;
2235 spec->autocfg.speaker_pins[1] = 0x16;
2236 spec->autocfg.speaker_pins[2] = 0x17;
2237 spec->autocfg.speaker_pins[3] = 0x19;
2238 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02002239 spec->automute = 1;
2240 spec->automute_mode = ALC_AUTOMUTE_AMP;
Wu Fengguang6732bd02009-07-30 09:19:14 +02002241}
2242
2243static void alc889_intel_init_hook(struct hda_codec *codec)
2244{
2245 alc889_coef_init(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02002246 alc_hp_automute(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02002247}
2248
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002249static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002250{
2251 struct alc_spec *spec = codec->spec;
2252
2253 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
2254 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
2255 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
2256 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaid922b512011-04-28 12:18:53 +02002257 spec->automute = 1;
2258 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002259}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002260
2261/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002262 * ALC888 Acer Aspire 4930G model
2263 */
2264
Takashi Iwaia9111322011-05-02 11:30:18 +02002265static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002266/* Front Mic: set to PIN_IN (empty by default) */
2267 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2268/* Unselect Front Mic by default in input mixer 3 */
2269 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002270/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002271 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2272/* Connect Internal HP to front */
2273 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2274 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2275 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2276/* Connect HP out to front */
2277 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2278 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2279 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie2e93292011-01-12 08:03:39 +01002280 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002281 { }
2282};
2283
Hector Martin3b315d72009-06-02 10:54:19 +02002284/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01002285 * ALC888 Acer Aspire 6530G model
2286 */
2287
Takashi Iwaia9111322011-05-02 11:30:18 +02002288static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01002289/* Route to built-in subwoofer as well as speakers */
2290 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2291 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2292 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2293 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002294/* Bias voltage on for external mic port */
2295 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02002296/* Front Mic: set to PIN_IN (empty by default) */
2297 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2298/* Unselect Front Mic by default in input mixer 3 */
2299 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002300/* Enable unsolicited event for HP jack */
2301 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2302/* Enable speaker output */
2303 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2304 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01002305 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002306/* Enable headphone output */
2307 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2308 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2309 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01002310 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002311 { }
2312};
2313
2314/*
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002315 *ALC888 Acer Aspire 7730G model
2316 */
2317
Takashi Iwaia9111322011-05-02 11:30:18 +02002318static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002319/* Bias voltage on for external mic port */
2320 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
2321/* Front Mic: set to PIN_IN (empty by default) */
2322 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2323/* Unselect Front Mic by default in input mixer 3 */
2324 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2325/* Enable unsolicited event for HP jack */
2326 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2327/* Enable speaker output */
2328 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2329 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2330 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
2331/* Enable headphone output */
2332 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2333 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2334 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2335 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
2336/*Enable internal subwoofer */
2337 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2338 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2339 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
2340 {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
2341 { }
2342};
2343
2344/*
Hector Martin018df412009-06-04 00:13:40 +02002345 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02002346 */
2347
Takashi Iwaia9111322011-05-02 11:30:18 +02002348static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02002349/* Front Mic: set to PIN_IN (empty by default) */
2350 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2351/* Unselect Front Mic by default in input mixer 3 */
2352 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2353/* Enable unsolicited event for HP jack */
2354 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2355/* Connect Internal Front to Front */
2356 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2357 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2358 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2359/* Connect Internal Rear to Rear */
2360 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2361 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2362 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2363/* Connect Internal CLFE to CLFE */
2364 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2365 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2366 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2367/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002368 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002369 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2370 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2371/* Enable all DACs */
2372/* DAC DISABLE/MUTE 1? */
2373/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2374 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2375 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2376/* DAC DISABLE/MUTE 2? */
2377/* some bit here disables the other DACs. Init=0x4900 */
2378 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2379 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002380/* DMIC fix
2381 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2382 * which makes the stereo useless. However, either the mic or the ALC889
2383 * makes the signal become a difference/sum signal instead of standard
2384 * stereo, which is annoying. So instead we flip this bit which makes the
2385 * codec replicate the sum signal to both channels, turning it into a
2386 * normal mono mic.
2387 */
2388/* DMIC_CONTROL? Init value = 0x0001 */
2389 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2390 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002391 { }
2392};
2393
Takashi Iwaia9111322011-05-02 11:30:18 +02002394static const struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002395 /* Front mic only available on one ADC */
2396 {
2397 .num_items = 4,
2398 .items = {
2399 { "Mic", 0x0 },
2400 { "Line", 0x2 },
2401 { "CD", 0x4 },
2402 { "Front Mic", 0xb },
2403 },
2404 },
2405 {
2406 .num_items = 3,
2407 .items = {
2408 { "Mic", 0x0 },
2409 { "Line", 0x2 },
2410 { "CD", 0x4 },
2411 },
2412 }
2413};
2414
Takashi Iwaia9111322011-05-02 11:30:18 +02002415static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01002416 /* Interal mic only available on one ADC */
2417 {
Tony Vroon684a8842009-06-26 09:27:50 +01002418 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002419 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002420 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002421 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002422 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002423 { "Input Mix", 0xa },
David Henningsson28c4edb2010-12-20 14:24:29 +01002424 { "Internal Mic", 0xb },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002425 },
2426 },
2427 {
Tony Vroon684a8842009-06-26 09:27:50 +01002428 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002429 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002430 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002431 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002432 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002433 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002434 },
2435 }
2436};
2437
Takashi Iwaia9111322011-05-02 11:30:18 +02002438static const struct hda_input_mux alc889_capture_sources[3] = {
Hector Martin018df412009-06-04 00:13:40 +02002439 /* Digital mic only available on first "ADC" */
2440 {
2441 .num_items = 5,
2442 .items = {
2443 { "Mic", 0x0 },
2444 { "Line", 0x2 },
2445 { "CD", 0x4 },
2446 { "Front Mic", 0xb },
2447 { "Input Mix", 0xa },
2448 },
2449 },
2450 {
2451 .num_items = 4,
2452 .items = {
2453 { "Mic", 0x0 },
2454 { "Line", 0x2 },
2455 { "CD", 0x4 },
2456 { "Input Mix", 0xa },
2457 },
2458 },
2459 {
2460 .num_items = 4,
2461 .items = {
2462 { "Mic", 0x0 },
2463 { "Line", 0x2 },
2464 { "CD", 0x4 },
2465 { "Input Mix", 0xa },
2466 },
2467 }
2468};
2469
Takashi Iwaia9111322011-05-02 11:30:18 +02002470static const struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002471 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2472 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2473 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2474 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2475 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2476 HDA_OUTPUT),
2477 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2478 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2479 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2480 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2481 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2482 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2483 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2484 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2485 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2486 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002487 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002488 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002489 { } /* end */
2490};
2491
Takashi Iwaia9111322011-05-02 11:30:18 +02002492static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002493 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2494 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2495 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2496 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002497 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002498 HDA_OUTPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002499 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2500 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2501 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2502 HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
2503 HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002504 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2505 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2506 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2507 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2508 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2509 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
2510 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2511 { } /* end */
2512};
2513
Takashi Iwaia9111322011-05-02 11:30:18 +02002514static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
Hector Martin556eea92009-12-20 22:51:23 +01002515 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2516 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2517 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2518 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2519 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2520 HDA_OUTPUT),
2521 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2522 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2523 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2524 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2525 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2526 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002527 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002528 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2529 { } /* end */
2530};
2531
2532
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002533static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002534{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002535 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002536
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002537 spec->autocfg.hp_pins[0] = 0x15;
2538 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002539 spec->autocfg.speaker_pins[1] = 0x16;
2540 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002541 spec->automute = 1;
2542 spec->automute_mode = ALC_AUTOMUTE_AMP;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002543}
2544
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002545static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002546{
2547 struct alc_spec *spec = codec->spec;
2548
2549 spec->autocfg.hp_pins[0] = 0x15;
2550 spec->autocfg.speaker_pins[0] = 0x14;
2551 spec->autocfg.speaker_pins[1] = 0x16;
2552 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002553 spec->automute = 1;
2554 spec->automute_mode = ALC_AUTOMUTE_AMP;
Emilio López320d5922009-06-25 08:18:44 +02002555}
2556
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002557static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2558{
2559 struct alc_spec *spec = codec->spec;
2560
2561 spec->autocfg.hp_pins[0] = 0x15;
2562 spec->autocfg.speaker_pins[0] = 0x14;
2563 spec->autocfg.speaker_pins[1] = 0x16;
2564 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002565 spec->automute = 1;
2566 spec->automute_mode = ALC_AUTOMUTE_AMP;
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002567}
2568
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002569static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002570{
2571 struct alc_spec *spec = codec->spec;
2572
2573 spec->autocfg.hp_pins[0] = 0x15;
2574 spec->autocfg.speaker_pins[0] = 0x14;
2575 spec->autocfg.speaker_pins[1] = 0x16;
2576 spec->autocfg.speaker_pins[2] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02002577 spec->automute = 1;
2578 spec->automute_mode = ALC_AUTOMUTE_AMP;
Hector Martin3b315d72009-06-02 10:54:19 +02002579}
2580
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002581/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002582 * ALC880 3-stack model
2583 *
2584 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002585 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2586 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 */
2588
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002589static const hda_nid_t alc880_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002590 /* front, rear, clfe, rear_surr */
2591 0x02, 0x05, 0x04, 0x03
2592};
2593
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002594static const hda_nid_t alc880_adc_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002595 /* ADC0-2 */
2596 0x07, 0x08, 0x09,
2597};
2598
2599/* The datasheet says the node 0x07 is connected from inputs,
2600 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002601 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002603static const hda_nid_t alc880_adc_nids_alt[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002604 /* ADC1-2 */
2605 0x08, 0x09,
2606};
2607
2608#define ALC880_DIGOUT_NID 0x06
2609#define ALC880_DIGIN_NID 0x0a
2610
Takashi Iwaia9111322011-05-02 11:30:18 +02002611static const struct hda_input_mux alc880_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002612 .num_items = 4,
2613 .items = {
2614 { "Mic", 0x0 },
2615 { "Front Mic", 0x3 },
2616 { "Line", 0x2 },
2617 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002619};
2620
2621/* channel source setting (2/6 channel selection for 3-stack) */
2622/* 2ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002623static const struct hda_verb alc880_threestack_ch2_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002624 /* set line-in to input, mute it */
2625 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2626 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2627 /* set mic-in to input vref 80%, mute it */
2628 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2629 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 { } /* end */
2631};
2632
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002633/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002634static const struct hda_verb alc880_threestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002635 /* set line-in to output, unmute it */
2636 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2637 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2638 /* set mic-in to output, unmute it */
2639 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2640 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2641 { } /* end */
2642};
2643
Takashi Iwaia9111322011-05-02 11:30:18 +02002644static const struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002645 { 2, alc880_threestack_ch2_init },
2646 { 6, alc880_threestack_ch6_init },
2647};
2648
Takashi Iwaia9111322011-05-02 11:30:18 +02002649static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002650 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002651 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002652 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002653 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002654 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2655 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002656 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2657 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2659 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2660 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2661 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2662 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2663 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2664 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2665 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002667 {
2668 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2669 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002670 .info = alc_ch_mode_info,
2671 .get = alc_ch_mode_get,
2672 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002673 },
2674 { } /* end */
2675};
2676
2677/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002678static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2679 struct snd_ctl_elem_info *uinfo)
2680{
2681 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2682 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002683 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002684 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002685
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002686 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002687 if (spec->vol_in_capsrc)
2688 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
2689 else
2690 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
2691 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002692 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002693 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002694 return err;
2695}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002697static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2698 unsigned int size, unsigned int __user *tlv)
2699{
2700 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2701 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002702 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002703 int err;
2704
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002705 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002706 if (spec->vol_in_capsrc)
2707 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
2708 else
2709 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
2710 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002711 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002712 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002713 return err;
2714}
2715
2716typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2717 struct snd_ctl_elem_value *ucontrol);
2718
2719static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2720 struct snd_ctl_elem_value *ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002721 getput_call_t func, bool check_adc_switch)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002722{
2723 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2724 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002725 int i, err;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002726
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002727 mutex_lock(&codec->control_mutex);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002728 if (check_adc_switch && spec->dual_adc_switch) {
2729 for (i = 0; i < spec->num_adc_nids; i++) {
2730 kcontrol->private_value =
2731 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2732 3, 0, HDA_INPUT);
2733 err = func(kcontrol, ucontrol);
2734 if (err < 0)
2735 goto error;
2736 }
2737 } else {
2738 i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002739 if (spec->vol_in_capsrc)
2740 kcontrol->private_value =
2741 HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i],
2742 3, 0, HDA_OUTPUT);
2743 else
2744 kcontrol->private_value =
2745 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2746 3, 0, HDA_INPUT);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002747 err = func(kcontrol, ucontrol);
2748 }
2749 error:
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002750 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002751 return err;
2752}
2753
2754static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2755 struct snd_ctl_elem_value *ucontrol)
2756{
2757 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002758 snd_hda_mixer_amp_volume_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002759}
2760
2761static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2762 struct snd_ctl_elem_value *ucontrol)
2763{
2764 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002765 snd_hda_mixer_amp_volume_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002766}
2767
2768/* capture mixer elements */
2769#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2770
2771static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2772 struct snd_ctl_elem_value *ucontrol)
2773{
2774 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002775 snd_hda_mixer_amp_switch_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002776}
2777
2778static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2779 struct snd_ctl_elem_value *ucontrol)
2780{
2781 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002782 snd_hda_mixer_amp_switch_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002783}
2784
Takashi Iwaia23b6882009-03-23 15:21:36 +01002785#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002786 { \
2787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2788 .name = "Capture Switch", \
2789 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2790 .count = num, \
2791 .info = alc_cap_sw_info, \
2792 .get = alc_cap_sw_get, \
2793 .put = alc_cap_sw_put, \
2794 }, \
2795 { \
2796 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2797 .name = "Capture Volume", \
2798 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2799 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2800 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2801 .count = num, \
2802 .info = alc_cap_vol_info, \
2803 .get = alc_cap_vol_get, \
2804 .put = alc_cap_vol_put, \
2805 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002806 }
2807
2808#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002809 { \
2810 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2811 /* .name = "Capture Source", */ \
2812 .name = "Input Source", \
2813 .count = num, \
2814 .info = alc_mux_enum_info, \
2815 .get = alc_mux_enum_get, \
2816 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002817 }
2818
2819#define DEFINE_CAPMIX(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002820static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002821 _DEFINE_CAPMIX(num), \
2822 _DEFINE_CAPSRC(num), \
2823 { } /* end */ \
2824}
2825
2826#define DEFINE_CAPMIX_NOSRC(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002827static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002828 _DEFINE_CAPMIX(num), \
2829 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002830}
2831
2832/* up to three ADCs */
2833DEFINE_CAPMIX(1);
2834DEFINE_CAPMIX(2);
2835DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002836DEFINE_CAPMIX_NOSRC(1);
2837DEFINE_CAPMIX_NOSRC(2);
2838DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002839
2840/*
2841 * ALC880 5-stack model
2842 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002843 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2844 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002845 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2846 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2847 */
2848
2849/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02002850static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002851 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002852 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 { } /* end */
2854};
2855
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002856/* channel source setting (6/8 channel selection for 5-stack) */
2857/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002858static const struct hda_verb alc880_fivestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002859 /* set line-in to input, mute it */
2860 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2861 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002862 { } /* end */
2863};
2864
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002865/* 8ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002866static const struct hda_verb alc880_fivestack_ch8_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002867 /* set line-in to output, unmute it */
2868 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2869 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2870 { } /* end */
2871};
2872
Takashi Iwaia9111322011-05-02 11:30:18 +02002873static const struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002874 { 6, alc880_fivestack_ch6_init },
2875 { 8, alc880_fivestack_ch8_init },
2876};
2877
2878
2879/*
2880 * ALC880 6-stack model
2881 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002882 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2883 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002884 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2885 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2886 */
2887
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002888static const hda_nid_t alc880_6st_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002889 /* front, rear, clfe, rear_surr */
2890 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002891};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002892
Takashi Iwaia9111322011-05-02 11:30:18 +02002893static const struct hda_input_mux alc880_6stack_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002894 .num_items = 4,
2895 .items = {
2896 { "Mic", 0x0 },
2897 { "Front Mic", 0x1 },
2898 { "Line", 0x2 },
2899 { "CD", 0x4 },
2900 },
2901};
2902
2903/* fixed 8-channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002904static const struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002905 { 8, NULL },
2906};
2907
Takashi Iwaia9111322011-05-02 11:30:18 +02002908static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002909 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002910 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002911 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002912 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002913 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2914 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002915 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2916 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002917 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002918 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002919 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2920 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2921 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2922 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2923 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2924 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2925 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2926 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002927 {
2928 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2929 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002930 .info = alc_ch_mode_info,
2931 .get = alc_ch_mode_get,
2932 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002933 },
2934 { } /* end */
2935};
2936
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002937
2938/*
2939 * ALC880 W810 model
2940 *
2941 * W810 has rear IO for:
2942 * Front (DAC 02)
2943 * Surround (DAC 03)
2944 * Center/LFE (DAC 04)
2945 * Digital out (06)
2946 *
2947 * The system also has a pair of internal speakers, and a headphone jack.
2948 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002949 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002950 * There is a variable resistor to control the speaker or headphone
2951 * volume. This is a hardware-only device without a software API.
2952 *
2953 * Plugging headphones in will disable the internal speakers. This is
2954 * implemented in hardware, not via the driver using jack sense. In
2955 * a similar fashion, plugging into the rear socket marked "front" will
2956 * disable both the speakers and headphones.
2957 *
2958 * For input, there's a microphone jack, and an "audio in" jack.
2959 * These may not do anything useful with this driver yet, because I
2960 * haven't setup any initialization verbs for these yet...
2961 */
2962
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002963static const hda_nid_t alc880_w810_dac_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002964 /* front, rear/surround, clfe */
2965 0x02, 0x03, 0x04
2966};
2967
2968/* fixed 6 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002969static const struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002970 { 6, NULL }
2971};
2972
2973/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaia9111322011-05-02 11:30:18 +02002974static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002975 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002976 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002977 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002978 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002979 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2980 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002981 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2982 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002983 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2984 { } /* end */
2985};
2986
2987
2988/*
2989 * Z710V model
2990 *
2991 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002992 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2993 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002994 */
2995
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002996static const hda_nid_t alc880_z71v_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002997 0x02
2998};
2999#define ALC880_Z71V_HP_DAC 0x03
3000
3001/* fixed 2 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02003002static const struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003003 { 2, NULL }
3004};
3005
Takashi Iwaia9111322011-05-02 11:30:18 +02003006static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003007 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003008 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003009 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003010 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003011 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3012 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3013 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3014 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3015 { } /* end */
3016};
3017
3018
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003019/*
3020 * ALC880 F1734 model
3021 *
3022 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
3023 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
3024 */
3025
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003026static const hda_nid_t alc880_f1734_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003027 0x03
3028};
3029#define ALC880_F1734_HP_DAC 0x02
3030
Takashi Iwaia9111322011-05-02 11:30:18 +02003031static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003032 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003033 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01003034 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3035 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003036 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3037 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01003038 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3039 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003040 { } /* end */
3041};
3042
Takashi Iwaia9111322011-05-02 11:30:18 +02003043static const struct hda_input_mux alc880_f1734_capture_source = {
Takashi Iwai937b4162008-02-11 14:52:36 +01003044 .num_items = 2,
3045 .items = {
3046 { "Mic", 0x1 },
3047 { "CD", 0x4 },
3048 },
3049};
3050
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003051
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003052/*
3053 * ALC880 ASUS model
3054 *
3055 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3056 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3057 * Mic = 0x18, Line = 0x1a
3058 */
3059
3060#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
3061#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
3062
Takashi Iwaia9111322011-05-02 11:30:18 +02003063static const struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003064 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003065 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003066 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003067 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003068 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3069 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003070 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3071 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003072 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3073 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3074 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3075 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3076 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3077 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003078 {
3079 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3080 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003081 .info = alc_ch_mode_info,
3082 .get = alc_ch_mode_get,
3083 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02003084 },
3085 { } /* end */
3086};
3087
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003088/*
3089 * ALC880 ASUS W1V model
3090 *
3091 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3092 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3093 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
3094 */
3095
3096/* additional mixers to alc880_asus_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02003097static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003098 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
3099 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003100 { } /* end */
3101};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003102
Kailang Yangdf694da2005-12-05 19:42:22 +01003103/* TCL S700 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003104static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003105 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3106 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3107 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
3108 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
3109 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
3110 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
3111 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
3112 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3113 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003114 { } /* end */
3115};
3116
Kailang Yangccc656c2006-10-17 12:32:26 +02003117/* Uniwill */
Takashi Iwaia9111322011-05-02 11:30:18 +02003118static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003119 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3120 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3121 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3122 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003123 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3124 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3125 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3126 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3127 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3128 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3129 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3130 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3131 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3132 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3133 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3134 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003135 {
3136 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3137 .name = "Channel Mode",
3138 .info = alc_ch_mode_info,
3139 .get = alc_ch_mode_get,
3140 .put = alc_ch_mode_put,
3141 },
3142 { } /* end */
3143};
3144
Takashi Iwaia9111322011-05-02 11:30:18 +02003145static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003146 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3147 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3148 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3149 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
3150 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3151 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01003152 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3153 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01003154 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3155 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003156 { } /* end */
3157};
3158
Takashi Iwaia9111322011-05-02 11:30:18 +02003159static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003160 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3161 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3162 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3163 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003164 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3165 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3166 { } /* end */
3167};
3168
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01003170 * virtual master controls
3171 */
3172
3173/*
3174 * slave controls for virtual master
3175 */
Takashi Iwaiea734962011-01-17 11:29:34 +01003176static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003177 "Front Playback Volume",
3178 "Surround Playback Volume",
3179 "Center Playback Volume",
3180 "LFE Playback Volume",
3181 "Side Playback Volume",
3182 "Headphone Playback Volume",
3183 "Speaker Playback Volume",
3184 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003185 "Line-Out Playback Volume",
3186 NULL,
3187};
3188
Takashi Iwaiea734962011-01-17 11:29:34 +01003189static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003190 "Front Playback Switch",
3191 "Surround Playback Switch",
3192 "Center Playback Switch",
3193 "LFE Playback Switch",
3194 "Side Playback Switch",
3195 "Headphone Playback Switch",
3196 "Speaker Playback Switch",
3197 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01003198 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01003199 "Line-Out Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003200 NULL,
3201};
3202
3203/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003204 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 */
Takashi Iwai603c4012008-07-30 15:01:44 +02003206
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003207#define NID_MAPPING (-1)
3208
3209#define SUBDEV_SPEAKER_ (0 << 6)
3210#define SUBDEV_HP_ (1 << 6)
3211#define SUBDEV_LINE_ (2 << 6)
3212#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
3213#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
3214#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
3215
Takashi Iwai603c4012008-07-30 15:01:44 +02003216static void alc_free_kctls(struct hda_codec *codec);
3217
Takashi Iwai67d634c2009-11-16 15:35:59 +01003218#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003219/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02003220static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003221 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003222 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003223 { } /* end */
3224};
Takashi Iwai67d634c2009-11-16 15:35:59 +01003225#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003226
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227static int alc_build_controls(struct hda_codec *codec)
3228{
3229 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02003230 struct snd_kcontrol *kctl = NULL;
Takashi Iwaia9111322011-05-02 11:30:18 +02003231 const struct snd_kcontrol_new *knew;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003232 int i, j, err;
3233 unsigned int u;
3234 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235
3236 for (i = 0; i < spec->num_mixers; i++) {
3237 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
3238 if (err < 0)
3239 return err;
3240 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003241 if (spec->cap_mixer) {
3242 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
3243 if (err < 0)
3244 return err;
3245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003247 err = snd_hda_create_spdif_out_ctls(codec,
Stephen Warren74b654c2011-06-01 11:14:18 -06003248 spec->multiout.dig_out_nid,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003249 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 if (err < 0)
3251 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003252 if (!spec->no_analog) {
3253 err = snd_hda_create_spdif_share_sw(codec,
3254 &spec->multiout);
3255 if (err < 0)
3256 return err;
3257 spec->multiout.share_spdif = 1;
3258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 }
3260 if (spec->dig_in_nid) {
3261 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3262 if (err < 0)
3263 return err;
3264 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01003265
Takashi Iwai67d634c2009-11-16 15:35:59 +01003266#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003267 /* create beep controls if needed */
3268 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02003269 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003270 for (knew = alc_beep_mixer; knew->name; knew++) {
3271 struct snd_kcontrol *kctl;
3272 kctl = snd_ctl_new1(knew, codec);
3273 if (!kctl)
3274 return -ENOMEM;
3275 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003276 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003277 if (err < 0)
3278 return err;
3279 }
3280 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01003281#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003282
Takashi Iwai2134ea42008-01-10 16:53:55 +01003283 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003284 if (!spec->no_analog &&
3285 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003286 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01003287 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003288 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003289 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003290 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003291 if (err < 0)
3292 return err;
3293 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003294 if (!spec->no_analog &&
3295 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003296 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
3297 NULL, alc_slave_sws);
3298 if (err < 0)
3299 return err;
3300 }
3301
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003302 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003303 if (spec->capsrc_nids || spec->adc_nids) {
3304 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
3305 if (!kctl)
3306 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3307 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003308 const hda_nid_t *nids = spec->capsrc_nids;
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003309 if (!nids)
3310 nids = spec->adc_nids;
3311 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3312 if (err < 0)
3313 return err;
3314 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003315 }
3316 if (spec->cap_mixer) {
3317 const char *kname = kctl ? kctl->id.name : NULL;
3318 for (knew = spec->cap_mixer; knew->name; knew++) {
3319 if (kname && strcmp(knew->name, kname) == 0)
3320 continue;
3321 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3322 for (i = 0; kctl && i < kctl->count; i++) {
3323 err = snd_hda_add_nid(codec, kctl, i,
3324 spec->adc_nids[i]);
3325 if (err < 0)
3326 return err;
3327 }
3328 }
3329 }
3330
3331 /* other nid->control mapping */
3332 for (i = 0; i < spec->num_mixers; i++) {
3333 for (knew = spec->mixers[i]; knew->name; knew++) {
3334 if (knew->iface != NID_MAPPING)
3335 continue;
3336 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3337 if (kctl == NULL)
3338 continue;
3339 u = knew->subdevice;
3340 for (j = 0; j < 4; j++, u >>= 8) {
3341 nid = u & 0x3f;
3342 if (nid == 0)
3343 continue;
3344 switch (u & 0xc0) {
3345 case SUBDEV_SPEAKER_:
3346 nid = spec->autocfg.speaker_pins[nid];
3347 break;
3348 case SUBDEV_LINE_:
3349 nid = spec->autocfg.line_out_pins[nid];
3350 break;
3351 case SUBDEV_HP_:
3352 nid = spec->autocfg.hp_pins[nid];
3353 break;
3354 default:
3355 continue;
3356 }
3357 err = snd_hda_add_nid(codec, kctl, 0, nid);
3358 if (err < 0)
3359 return err;
3360 }
3361 u = knew->private_value;
3362 for (j = 0; j < 4; j++, u >>= 8) {
3363 nid = u & 0xff;
3364 if (nid == 0)
3365 continue;
3366 err = snd_hda_add_nid(codec, kctl, 0, nid);
3367 if (err < 0)
3368 return err;
3369 }
3370 }
3371 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003372
3373 alc_free_kctls(codec); /* no longer needed */
3374
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 return 0;
3376}
3377
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003378
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379/*
3380 * initialize the codec volumes, etc
3381 */
3382
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003383/*
3384 * generic initialization of ADC, input mixers and output mixers
3385 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003386static const struct hda_verb alc880_volume_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003387 /*
3388 * Unmute ADC0-2 and set the default input to mic-in
3389 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003390 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003391 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003392 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003393 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003394 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003395 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003397 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3398 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003399 * Note: PASD motherboards uses the Line In 2 as the input for front
3400 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003402 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003403 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3404 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3405 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3406 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3407 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3408 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3409 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003411 /*
3412 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003414 /* set vol=0 to output mixers */
3415 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3416 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3417 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3418 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3419 /* set up input amps for analog loopback */
3420 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003421 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003423 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3424 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003425 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003427 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3428 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429
3430 { }
3431};
3432
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003433/*
3434 * 3-stack pin configuration:
3435 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3436 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003437static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003438 /*
3439 * preset connection lists of input pins
3440 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3441 */
3442 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3443 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3444 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3445
3446 /*
3447 * Set pin mode and muting
3448 */
3449 /* set front pin widgets 0x14 for output */
3450 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3451 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3452 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3453 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3454 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3455 /* Mic2 (as headphone out) for HP output */
3456 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3457 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3458 /* Line In pin widget for input */
3459 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3460 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3461 /* Line2 (as front mic) pin widget for input and vref at 80% */
3462 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3463 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3464 /* CD pin widget for input */
3465 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3466
3467 { }
3468};
3469
3470/*
3471 * 5-stack pin configuration:
3472 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3473 * line-in/side = 0x1a, f-mic = 0x1b
3474 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003475static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003476 /*
3477 * preset connection lists of input pins
3478 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3479 */
3480 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3481 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3482
3483 /*
3484 * Set pin mode and muting
3485 */
3486 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003487 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3488 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3489 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3490 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003491 /* unmute pins for output (no gain on this amp) */
3492 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3493 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3494 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3495 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3496
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003498 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003499 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3500 /* Mic2 (as headphone out) for HP output */
3501 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003502 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003503 /* Line In pin widget for input */
3504 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3505 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3506 /* Line2 (as front mic) pin widget for input and vref at 80% */
3507 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3508 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3509 /* CD pin widget for input */
3510 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511
3512 { }
3513};
3514
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003515/*
3516 * W810 pin configuration:
3517 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3518 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003519static const struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 /* hphone/speaker input selector: front DAC */
3521 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3522
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003523 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3524 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3525 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3526 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3527 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3528 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3529
3530 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003531 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 { }
3534};
3535
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003536/*
3537 * Z71V pin configuration:
3538 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3539 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003540static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003541 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003542 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003543 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003544 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003545
Takashi Iwai16ded522005-06-10 19:58:24 +02003546 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003547 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003548 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003549 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003550
3551 { }
3552};
3553
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003554/*
3555 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003556 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3557 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003558 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003559static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003560 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3561
Takashi Iwai16ded522005-06-10 19:58:24 +02003562 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003563 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003564 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003565 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003566 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003567 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003568 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003569 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3570
Takashi Iwai16ded522005-06-10 19:58:24 +02003571 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003572 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003573 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003574 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003575 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003576 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003577 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003578 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003579 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003580
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003581 { }
3582};
Takashi Iwai16ded522005-06-10 19:58:24 +02003583
Kailang Yangccc656c2006-10-17 12:32:26 +02003584/*
3585 * Uniwill pin configuration:
3586 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3587 * line = 0x1a
3588 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003589static const struct hda_verb alc880_uniwill_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003590 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3591
3592 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3593 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3594 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3595 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3596 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3597 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3598 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3599 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3600 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3601 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3602 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3603 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3604 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3605 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3606
3607 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3608 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3609 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3610 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3611 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3612 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3613 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3614 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3615 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3616
3617 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3618 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3619
3620 { }
3621};
3622
3623/*
3624* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003625* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003626 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003627static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003628 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3629
3630 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3631 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3632 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3633 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3634 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3635 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3636 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3637 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3638 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3639 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3640 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3641 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3642
3643 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3644 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3645 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3646 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3647 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3648 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3649
3650 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3651 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3652
3653 { }
3654};
3655
Takashi Iwaia9111322011-05-02 11:30:18 +02003656static const struct hda_verb alc880_beep_init_verbs[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003657 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3658 { }
3659};
3660
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003661/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003662static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003663{
3664 unsigned int present;
3665 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003666
Wu Fengguang864f92b2009-11-18 12:38:02 +08003667 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003668 bits = present ? HDA_AMP_MUTE : 0;
3669 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003670}
3671
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003672static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003673{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003674 struct alc_spec *spec = codec->spec;
3675
3676 spec->autocfg.hp_pins[0] = 0x14;
3677 spec->autocfg.speaker_pins[0] = 0x15;
3678 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02003679 spec->automute = 1;
3680 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003681}
3682
3683static void alc880_uniwill_init_hook(struct hda_codec *codec)
3684{
Takashi Iwaid922b512011-04-28 12:18:53 +02003685 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003686 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003687}
3688
3689static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3690 unsigned int res)
3691{
3692 /* Looks like the unsol event is incompatible with the standard
3693 * definition. 4bit tag is placed at 28 bit!
3694 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003695 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003696 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003697 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003698 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003699 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02003700 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003701 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003702 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003703}
3704
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003705static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003706{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003707 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003708
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003709 spec->autocfg.hp_pins[0] = 0x14;
3710 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02003711 spec->automute = 1;
3712 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangccc656c2006-10-17 12:32:26 +02003713}
3714
3715static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3716{
3717 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003718
Kailang Yangccc656c2006-10-17 12:32:26 +02003719 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003720 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3721 present &= HDA_AMP_VOLMASK;
3722 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3723 HDA_AMP_VOLMASK, present);
3724 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3725 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003726}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003727
Kailang Yangccc656c2006-10-17 12:32:26 +02003728static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3729 unsigned int res)
3730{
3731 /* Looks like the unsol event is incompatible with the standard
3732 * definition. 4bit tag is placed at 28 bit!
3733 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003734 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003735 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003736 else
Takashi Iwaid922b512011-04-28 12:18:53 +02003737 alc_sku_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003738}
3739
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003740/*
3741 * F1734 pin configuration:
3742 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3743 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003744static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003745 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003746 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3747 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3748 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3749 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3750
3751 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3752 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3753 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3754 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3755
3756 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3757 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003758 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003759 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3760 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3761 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3762 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3763 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3764 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003765
Takashi Iwai937b4162008-02-11 14:52:36 +01003766 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3767 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3768
Takashi Iwai16ded522005-06-10 19:58:24 +02003769 { }
3770};
3771
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003772/*
3773 * ASUS pin configuration:
3774 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3775 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003776static const struct hda_verb alc880_pin_asus_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003777 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3778 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3779 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3780 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3781
3782 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3783 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3784 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3785 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3786 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3787 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3788 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3789 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3790
3791 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3792 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3793 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3794 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3795 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3796 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3797 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3798 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3799 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003800
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003801 { }
3802};
3803
3804/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003805#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3806#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003807#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003808
Kailang Yangdf694da2005-12-05 19:42:22 +01003809/* Clevo m520g init */
Takashi Iwaia9111322011-05-02 11:30:18 +02003810static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003811 /* headphone output */
3812 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3813 /* line-out */
3814 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3815 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3816 /* Line-in */
3817 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3818 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3819 /* CD */
3820 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3821 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3822 /* Mic1 (rear panel) */
3823 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3824 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3825 /* Mic2 (front panel) */
3826 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3827 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3828 /* headphone */
3829 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3830 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3831 /* change to EAPD mode */
3832 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3833 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3834
3835 { }
3836};
3837
Takashi Iwaia9111322011-05-02 11:30:18 +02003838static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003839 /* change to EAPD mode */
3840 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3841 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3842
Kailang Yangdf694da2005-12-05 19:42:22 +01003843 /* Headphone output */
3844 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3845 /* Front output*/
3846 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3847 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3848
3849 /* Line In pin widget for input */
3850 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3851 /* CD pin widget for input */
3852 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3853 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3854 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3855
3856 /* change to EAPD mode */
3857 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3858 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3859
3860 { }
3861};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003862
3863/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003864 * LG m1 express dual
3865 *
3866 * Pin assignment:
3867 * Rear Line-In/Out (blue): 0x14
3868 * Build-in Mic-In: 0x15
3869 * Speaker-out: 0x17
3870 * HP-Out (green): 0x1b
3871 * Mic-In/Out (red): 0x19
3872 * SPDIF-Out: 0x1e
3873 */
3874
3875/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003876static const hda_nid_t alc880_lg_dac_nids[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003877 0x05, 0x02, 0x03
3878};
3879
3880/* seems analog CD is not working */
Takashi Iwaia9111322011-05-02 11:30:18 +02003881static const struct hda_input_mux alc880_lg_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003882 .num_items = 3,
3883 .items = {
3884 { "Mic", 0x1 },
3885 { "Line", 0x5 },
3886 { "Internal Mic", 0x6 },
3887 },
3888};
3889
3890/* 2,4,6 channel modes */
Takashi Iwaia9111322011-05-02 11:30:18 +02003891static const struct hda_verb alc880_lg_ch2_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003892 /* set line-in and mic-in to input */
3893 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3894 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3895 { }
3896};
3897
Takashi Iwaia9111322011-05-02 11:30:18 +02003898static const struct hda_verb alc880_lg_ch4_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003899 /* set line-in to out and mic-in to input */
3900 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3901 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3902 { }
3903};
3904
Takashi Iwaia9111322011-05-02 11:30:18 +02003905static const struct hda_verb alc880_lg_ch6_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003906 /* set line-in and mic-in to output */
3907 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3908 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3909 { }
3910};
3911
Takashi Iwaia9111322011-05-02 11:30:18 +02003912static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003913 { 2, alc880_lg_ch2_init },
3914 { 4, alc880_lg_ch4_init },
3915 { 6, alc880_lg_ch6_init },
3916};
3917
Takashi Iwaia9111322011-05-02 11:30:18 +02003918static const struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003919 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3920 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003921 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3922 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3923 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3924 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3925 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3926 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3927 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3928 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3929 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3930 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3931 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3932 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3933 {
3934 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3935 .name = "Channel Mode",
3936 .info = alc_ch_mode_info,
3937 .get = alc_ch_mode_get,
3938 .put = alc_ch_mode_put,
3939 },
3940 { } /* end */
3941};
3942
Takashi Iwaia9111322011-05-02 11:30:18 +02003943static const struct hda_verb alc880_lg_init_verbs[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003944 /* set capture source to mic-in */
3945 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3946 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3947 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3948 /* mute all amp mixer inputs */
3949 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003950 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3951 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003952 /* line-in to input */
3953 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3954 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3955 /* built-in mic */
3956 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3957 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3958 /* speaker-out */
3959 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3960 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3961 /* mic-in to input */
3962 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3963 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3964 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3965 /* HP-out */
3966 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3967 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3968 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3969 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003970 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003971 { }
3972};
3973
3974/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003975static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003976{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003977 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003978
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003979 spec->autocfg.hp_pins[0] = 0x1b;
3980 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02003981 spec->automute = 1;
3982 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003983}
3984
3985/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003986 * LG LW20
3987 *
3988 * Pin assignment:
3989 * Speaker-out: 0x14
3990 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003991 * Built-in Mic-In: 0x19
3992 * Line-In: 0x1b
3993 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003994 * SPDIF-Out: 0x1e
3995 */
3996
Takashi Iwaia9111322011-05-02 11:30:18 +02003997static const struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003998 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003999 .items = {
4000 { "Mic", 0x0 },
4001 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02004002 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004003 },
4004};
4005
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004006#define alc880_lg_lw_modes alc880_threestack_modes
4007
Takashi Iwaia9111322011-05-02 11:30:18 +02004008static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004009 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4010 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4011 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
4012 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
4013 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
4014 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
4015 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
4016 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
4017 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4018 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01004019 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4020 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4021 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
4022 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004023 {
4024 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4025 .name = "Channel Mode",
4026 .info = alc_ch_mode_info,
4027 .get = alc_ch_mode_get,
4028 .put = alc_ch_mode_put,
4029 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004030 { } /* end */
4031};
4032
Takashi Iwaia9111322011-05-02 11:30:18 +02004033static const struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004034 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4035 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
4036 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
4037
Takashi Iwaid6815182006-03-23 16:06:23 +01004038 /* set capture source to mic-in */
4039 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4040 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4041 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02004042 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01004043 /* speaker-out */
4044 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4045 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4046 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01004047 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4048 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4049 /* mic-in to input */
4050 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4051 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4052 /* built-in mic */
4053 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4054 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4055 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004056 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01004057 { }
4058};
4059
4060/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004061static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01004062{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004063 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01004064
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004065 spec->autocfg.hp_pins[0] = 0x1b;
4066 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02004067 spec->automute = 1;
4068 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaid6815182006-03-23 16:06:23 +01004069}
4070
Takashi Iwaia9111322011-05-02 11:30:18 +02004071static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004072 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4073 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
4074 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4075 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4076 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
4077 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
4078 { } /* end */
4079};
4080
Takashi Iwaia9111322011-05-02 11:30:18 +02004081static const struct hda_input_mux alc880_medion_rim_capture_source = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004082 .num_items = 2,
4083 .items = {
4084 { "Mic", 0x0 },
4085 { "Internal Mic", 0x1 },
4086 },
4087};
4088
Takashi Iwaia9111322011-05-02 11:30:18 +02004089static const struct hda_verb alc880_medion_rim_init_verbs[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004090 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4091
4092 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4093 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4094
4095 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4096 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4097 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4098 /* Mic2 (as headphone out) for HP output */
4099 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4100 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4101 /* Internal Speaker */
4102 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4103 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4104
4105 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
4106 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
4107
4108 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4109 { }
4110};
4111
4112/* toggle speaker-output according to the hp-jack state */
4113static void alc880_medion_rim_automute(struct hda_codec *codec)
4114{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004115 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02004116 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004117 /* toggle EAPD */
4118 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004119 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
4120 else
4121 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
4122}
4123
4124static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
4125 unsigned int res)
4126{
4127 /* Looks like the unsol event is incompatible with the standard
4128 * definition. 4bit tag is placed at 28 bit!
4129 */
4130 if ((res >> 28) == ALC880_HP_EVENT)
4131 alc880_medion_rim_automute(codec);
4132}
4133
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004134static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004135{
4136 struct alc_spec *spec = codec->spec;
4137
4138 spec->autocfg.hp_pins[0] = 0x14;
4139 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02004140 spec->automute = 1;
4141 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004142}
4143
Takashi Iwaicb53c622007-08-10 17:21:45 +02004144#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02004145static const struct hda_amp_list alc880_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004146 { 0x0b, HDA_INPUT, 0 },
4147 { 0x0b, HDA_INPUT, 1 },
4148 { 0x0b, HDA_INPUT, 2 },
4149 { 0x0b, HDA_INPUT, 3 },
4150 { 0x0b, HDA_INPUT, 4 },
4151 { } /* end */
4152};
4153
Takashi Iwaia9111322011-05-02 11:30:18 +02004154static const struct hda_amp_list alc880_lg_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004155 { 0x0b, HDA_INPUT, 1 },
4156 { 0x0b, HDA_INPUT, 6 },
4157 { 0x0b, HDA_INPUT, 7 },
4158 { } /* end */
4159};
4160#endif
4161
Takashi Iwaid6815182006-03-23 16:06:23 +01004162/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004163 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004164 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004165
Takashi Iwai584c0c42011-03-10 12:51:11 +01004166static void alc_init_special_input_src(struct hda_codec *codec);
4167
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168static int alc_init(struct hda_codec *codec)
4169{
4170 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004171 unsigned int i;
4172
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004173 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004174 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004175
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004176 for (i = 0; i < spec->num_init_verbs; i++)
4177 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai584c0c42011-03-10 12:51:11 +01004178 alc_init_special_input_src(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004179
4180 if (spec->init_hook)
4181 spec->init_hook(codec);
4182
Takashi Iwai58701122011-01-13 15:41:45 +01004183 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
4184
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004185 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 return 0;
4187}
4188
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004189static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
4190{
4191 struct alc_spec *spec = codec->spec;
4192
4193 if (spec->unsol_event)
4194 spec->unsol_event(codec, res);
4195}
4196
Takashi Iwaicb53c622007-08-10 17:21:45 +02004197#ifdef CONFIG_SND_HDA_POWER_SAVE
4198static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
4199{
4200 struct alc_spec *spec = codec->spec;
4201 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
4202}
4203#endif
4204
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205/*
4206 * Analog playback callbacks
4207 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004208static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004210 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211{
4212 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01004213 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
4214 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215}
4216
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004217static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 struct hda_codec *codec,
4219 unsigned int stream_tag,
4220 unsigned int format,
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;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004224 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
4225 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226}
4227
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004228static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004230 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231{
4232 struct alc_spec *spec = codec->spec;
4233 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
4234}
4235
4236/*
4237 * Digital out
4238 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004239static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004241 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242{
4243 struct alc_spec *spec = codec->spec;
4244 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
4245}
4246
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004247static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004248 struct hda_codec *codec,
4249 unsigned int stream_tag,
4250 unsigned int format,
4251 struct snd_pcm_substream *substream)
4252{
4253 struct alc_spec *spec = codec->spec;
4254 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
4255 stream_tag, format, substream);
4256}
4257
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004258static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004259 struct hda_codec *codec,
4260 struct snd_pcm_substream *substream)
4261{
4262 struct alc_spec *spec = codec->spec;
4263 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
4264}
4265
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004266static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004268 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269{
4270 struct alc_spec *spec = codec->spec;
4271 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4272}
4273
4274/*
4275 * Analog capture
4276 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004277static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 struct hda_codec *codec,
4279 unsigned int stream_tag,
4280 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004281 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282{
4283 struct alc_spec *spec = codec->spec;
4284
Takashi Iwai63300792008-01-24 15:31:36 +01004285 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 stream_tag, 0, format);
4287 return 0;
4288}
4289
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004290static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004292 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293{
4294 struct alc_spec *spec = codec->spec;
4295
Takashi Iwai888afa12008-03-18 09:57:50 +01004296 snd_hda_codec_cleanup_stream(codec,
4297 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 return 0;
4299}
4300
Takashi Iwai840b64c2010-07-13 22:49:01 +02004301/* analog capture with dynamic dual-adc changes */
4302static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4303 struct hda_codec *codec,
4304 unsigned int stream_tag,
4305 unsigned int format,
4306 struct snd_pcm_substream *substream)
4307{
4308 struct alc_spec *spec = codec->spec;
4309 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
4310 spec->cur_adc_stream_tag = stream_tag;
4311 spec->cur_adc_format = format;
4312 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
4313 return 0;
4314}
4315
4316static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4317 struct hda_codec *codec,
4318 struct snd_pcm_substream *substream)
4319{
4320 struct alc_spec *spec = codec->spec;
4321 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4322 spec->cur_adc = 0;
4323 return 0;
4324}
4325
Takashi Iwaia9111322011-05-02 11:30:18 +02004326static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02004327 .substreams = 1,
4328 .channels_min = 2,
4329 .channels_max = 2,
4330 .nid = 0, /* fill later */
4331 .ops = {
4332 .prepare = dualmic_capture_pcm_prepare,
4333 .cleanup = dualmic_capture_pcm_cleanup
4334 },
4335};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
4337/*
4338 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004339static const struct hda_pcm_stream alc_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 .substreams = 1,
4341 .channels_min = 2,
4342 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004343 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004345 .open = alc_playback_pcm_open,
4346 .prepare = alc_playback_pcm_prepare,
4347 .cleanup = alc_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 },
4349};
4350
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004351static const struct hda_pcm_stream alc_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004352 .substreams = 1,
4353 .channels_min = 2,
4354 .channels_max = 2,
4355 /* NID is set in alc_build_pcms */
4356};
4357
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004358static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01004359 .substreams = 1,
4360 .channels_min = 2,
4361 .channels_max = 2,
4362 /* NID is set in alc_build_pcms */
4363};
4364
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004365static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004366 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 .channels_min = 2,
4368 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004369 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004371 .prepare = alc_alt_capture_pcm_prepare,
4372 .cleanup = alc_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 },
4374};
4375
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004376static const struct hda_pcm_stream alc_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 .substreams = 1,
4378 .channels_min = 2,
4379 .channels_max = 2,
4380 /* NID is set in alc_build_pcms */
4381 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004382 .open = alc_dig_playback_pcm_open,
4383 .close = alc_dig_playback_pcm_close,
4384 .prepare = alc_dig_playback_pcm_prepare,
4385 .cleanup = alc_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 },
4387};
4388
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004389static const struct hda_pcm_stream alc_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 .substreams = 1,
4391 .channels_min = 2,
4392 .channels_max = 2,
4393 /* NID is set in alc_build_pcms */
4394};
4395
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004396/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02004397static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004398 .substreams = 0,
4399 .channels_min = 0,
4400 .channels_max = 0,
4401};
4402
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403static int alc_build_pcms(struct hda_codec *codec)
4404{
4405 struct alc_spec *spec = codec->spec;
4406 struct hda_pcm *info = spec->pcm_rec;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004407 const struct hda_pcm_stream *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 int i;
4409
4410 codec->num_pcms = 1;
4411 codec->pcm_info = info;
4412
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004413 if (spec->no_analog)
4414 goto skip_analog;
4415
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004416 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4417 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004419
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004420 if (spec->multiout.dac_nids > 0) {
4421 p = spec->stream_analog_playback;
4422 if (!p)
4423 p = &alc_pcm_analog_playback;
4424 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004425 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4426 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004427 if (spec->adc_nids) {
4428 p = spec->stream_analog_capture;
4429 if (!p)
4430 p = &alc_pcm_analog_capture;
4431 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004432 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Takashi Iwai4a471b72005-12-07 13:56:29 +01004435 if (spec->channel_mode) {
4436 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4437 for (i = 0; i < spec->num_channel_mode; i++) {
4438 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4439 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 }
4442 }
4443
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004444 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004445 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004447 snprintf(spec->stream_name_digital,
4448 sizeof(spec->stream_name_digital),
4449 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004450 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004451 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004452 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004454 if (spec->dig_out_type)
4455 info->pcm_type = spec->dig_out_type;
4456 else
4457 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004458 if (spec->multiout.dig_out_nid) {
4459 p = spec->stream_digital_playback;
4460 if (!p)
4461 p = &alc_pcm_digital_playback;
4462 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4464 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004465 if (spec->dig_in_nid) {
4466 p = spec->stream_digital_capture;
4467 if (!p)
4468 p = &alc_pcm_digital_capture;
4469 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4471 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004472 /* FIXME: do we need this for all Realtek codec models? */
4473 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 }
4475
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004476 if (spec->no_analog)
4477 return 0;
4478
Takashi Iwaie08a0072006-09-07 17:52:14 +02004479 /* If the use of more than one ADC is requested for the current
4480 * model, configure a second analog capture-only PCM.
4481 */
4482 /* Additional Analaog capture for index #2 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004483 if (spec->alt_dac_nid || spec->num_adc_nids > 1) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004484 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004485 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004486 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004487 if (spec->alt_dac_nid) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004488 p = spec->stream_analog_alt_playback;
4489 if (!p)
4490 p = &alc_pcm_analog_alt_playback;
4491 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01004492 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4493 spec->alt_dac_nid;
4494 } else {
4495 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4496 alc_pcm_null_stream;
4497 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4498 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004499 if (spec->num_adc_nids > 1) {
4500 p = spec->stream_analog_alt_capture;
4501 if (!p)
4502 p = &alc_pcm_analog_alt_capture;
4503 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01004504 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4505 spec->adc_nids[1];
4506 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4507 spec->num_adc_nids - 1;
4508 } else {
4509 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4510 alc_pcm_null_stream;
4511 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004512 }
4513 }
4514
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 return 0;
4516}
4517
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004518static inline void alc_shutup(struct hda_codec *codec)
4519{
Takashi Iwai1c716152011-04-07 10:37:16 +02004520 struct alc_spec *spec = codec->spec;
4521
4522 if (spec && spec->shutup)
4523 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004524 snd_hda_shutup_pins(codec);
4525}
4526
Takashi Iwai603c4012008-07-30 15:01:44 +02004527static void alc_free_kctls(struct hda_codec *codec)
4528{
4529 struct alc_spec *spec = codec->spec;
4530
4531 if (spec->kctls.list) {
4532 struct snd_kcontrol_new *kctl = spec->kctls.list;
4533 int i;
4534 for (i = 0; i < spec->kctls.used; i++)
4535 kfree(kctl[i].name);
4536 }
4537 snd_array_free(&spec->kctls);
4538}
4539
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540static void alc_free(struct hda_codec *codec)
4541{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004542 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004543
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004544 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004545 return;
4546
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004547 alc_shutup(codec);
Takashi Iwaicd372fb2011-03-03 14:40:14 +01004548 snd_hda_input_jack_free(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004549 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004550 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004551 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552}
4553
Hector Martinf5de24b2009-12-20 22:51:31 +01004554#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004555static void alc_power_eapd(struct hda_codec *codec)
4556{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02004557 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004558}
4559
Hector Martinf5de24b2009-12-20 22:51:31 +01004560static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4561{
4562 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004563 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004564 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004565 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004566 return 0;
4567}
4568#endif
4569
Takashi Iwaie044c392008-10-27 16:56:24 +01004570#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004571static int alc_resume(struct hda_codec *codec)
4572{
Takashi Iwai1c716152011-04-07 10:37:16 +02004573 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01004574 codec->patch_ops.init(codec);
4575 snd_hda_codec_resume_amp(codec);
4576 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004577 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004578 return 0;
4579}
Takashi Iwaie044c392008-10-27 16:56:24 +01004580#endif
4581
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582/*
4583 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004584static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 .build_controls = alc_build_controls,
4586 .build_pcms = alc_build_pcms,
4587 .init = alc_init,
4588 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004589 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004590#ifdef SND_HDA_NEEDS_RESUME
4591 .resume = alc_resume,
4592#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004593#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004594 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004595 .check_power_status = alc_check_power_status,
4596#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004597 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598};
4599
Kailang Yangc027ddc2010-03-19 11:33:06 +01004600/* replace the codec chip_name with the given string */
4601static int alc_codec_rename(struct hda_codec *codec, const char *name)
4602{
4603 kfree(codec->chip_name);
4604 codec->chip_name = kstrdup(name, GFP_KERNEL);
4605 if (!codec->chip_name) {
4606 alc_free(codec);
4607 return -ENOMEM;
4608 }
4609 return 0;
4610}
4611
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004612/*
4613 * Test configuration for debugging
4614 *
4615 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4616 * enum controls.
4617 */
4618#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004619static const hda_nid_t alc880_test_dac_nids[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004620 0x02, 0x03, 0x04, 0x05
4621};
4622
Takashi Iwaia9111322011-05-02 11:30:18 +02004623static const struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004624 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004625 .items = {
4626 { "In-1", 0x0 },
4627 { "In-2", 0x1 },
4628 { "In-3", 0x2 },
4629 { "In-4", 0x3 },
4630 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004631 { "Front", 0x5 },
4632 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004633 },
4634};
4635
Takashi Iwaia9111322011-05-02 11:30:18 +02004636static const struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004637 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004638 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004639 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004640 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004641};
4642
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004643static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4644 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004645{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004646 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004647 "N/A", "Line Out", "HP Out",
4648 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4649 };
4650 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4651 uinfo->count = 1;
4652 uinfo->value.enumerated.items = 8;
4653 if (uinfo->value.enumerated.item >= 8)
4654 uinfo->value.enumerated.item = 7;
4655 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4656 return 0;
4657}
4658
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004659static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4660 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004661{
4662 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4663 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4664 unsigned int pin_ctl, item = 0;
4665
4666 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4667 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4668 if (pin_ctl & AC_PINCTL_OUT_EN) {
4669 if (pin_ctl & AC_PINCTL_HP_EN)
4670 item = 2;
4671 else
4672 item = 1;
4673 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4674 switch (pin_ctl & AC_PINCTL_VREFEN) {
4675 case AC_PINCTL_VREF_HIZ: item = 3; break;
4676 case AC_PINCTL_VREF_50: item = 4; break;
4677 case AC_PINCTL_VREF_GRD: item = 5; break;
4678 case AC_PINCTL_VREF_80: item = 6; break;
4679 case AC_PINCTL_VREF_100: item = 7; break;
4680 }
4681 }
4682 ucontrol->value.enumerated.item[0] = item;
4683 return 0;
4684}
4685
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004686static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4687 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004688{
4689 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4690 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004691 static const unsigned int ctls[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004692 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4693 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4694 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4695 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4696 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4697 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4698 };
4699 unsigned int old_ctl, new_ctl;
4700
4701 old_ctl = snd_hda_codec_read(codec, nid, 0,
4702 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4703 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4704 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004705 int val;
4706 snd_hda_codec_write_cache(codec, nid, 0,
4707 AC_VERB_SET_PIN_WIDGET_CONTROL,
4708 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004709 val = ucontrol->value.enumerated.item[0] >= 3 ?
4710 HDA_AMP_MUTE : 0;
4711 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4712 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004713 return 1;
4714 }
4715 return 0;
4716}
4717
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004718static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4719 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004720{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004721 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004722 "Front", "Surround", "CLFE", "Side"
4723 };
4724 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4725 uinfo->count = 1;
4726 uinfo->value.enumerated.items = 4;
4727 if (uinfo->value.enumerated.item >= 4)
4728 uinfo->value.enumerated.item = 3;
4729 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4730 return 0;
4731}
4732
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004733static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4734 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004735{
4736 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4737 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4738 unsigned int sel;
4739
4740 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4741 ucontrol->value.enumerated.item[0] = sel & 3;
4742 return 0;
4743}
4744
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004745static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4746 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004747{
4748 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4749 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4750 unsigned int sel;
4751
4752 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4753 if (ucontrol->value.enumerated.item[0] != sel) {
4754 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004755 snd_hda_codec_write_cache(codec, nid, 0,
4756 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004757 return 1;
4758 }
4759 return 0;
4760}
4761
4762#define PIN_CTL_TEST(xname,nid) { \
4763 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4764 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004765 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004766 .info = alc_test_pin_ctl_info, \
4767 .get = alc_test_pin_ctl_get, \
4768 .put = alc_test_pin_ctl_put, \
4769 .private_value = nid \
4770 }
4771
4772#define PIN_SRC_TEST(xname,nid) { \
4773 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4774 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004775 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004776 .info = alc_test_pin_src_info, \
4777 .get = alc_test_pin_src_get, \
4778 .put = alc_test_pin_src_put, \
4779 .private_value = nid \
4780 }
4781
Takashi Iwaia9111322011-05-02 11:30:18 +02004782static const struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004783 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4784 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4785 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4786 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004787 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4788 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4789 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4790 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004791 PIN_CTL_TEST("Front Pin Mode", 0x14),
4792 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4793 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4794 PIN_CTL_TEST("Side Pin Mode", 0x17),
4795 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4796 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4797 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4798 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4799 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4800 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4801 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4802 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4803 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4804 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4805 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4806 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4807 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4808 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4809 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4810 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4811 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4812 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004813 {
4814 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4815 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004816 .info = alc_ch_mode_info,
4817 .get = alc_ch_mode_get,
4818 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004819 },
4820 { } /* end */
4821};
4822
Takashi Iwaia9111322011-05-02 11:30:18 +02004823static const struct hda_verb alc880_test_init_verbs[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004824 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004825 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4826 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4827 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4828 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4829 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4830 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4831 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4832 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004833 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004834 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4835 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4836 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4837 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004838 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004839 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4840 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4841 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4842 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004843 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004844 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4845 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4846 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4847 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004848 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004849 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4850 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004851 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4852 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4853 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004854 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004855 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4856 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4857 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4858 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004859 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004860 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004861 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004862 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004863 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004864 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004865 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004866 /* Analog input/passthru */
4867 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4868 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4869 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4870 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4871 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004872 { }
4873};
4874#endif
4875
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876/*
4877 */
4878
Takashi Iwaiea734962011-01-17 11:29:34 +01004879static const char * const alc880_models[ALC880_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004880 [ALC880_3ST] = "3stack",
4881 [ALC880_TCL_S700] = "tcl",
4882 [ALC880_3ST_DIG] = "3stack-digout",
4883 [ALC880_CLEVO] = "clevo",
4884 [ALC880_5ST] = "5stack",
4885 [ALC880_5ST_DIG] = "5stack-digout",
4886 [ALC880_W810] = "w810",
4887 [ALC880_Z71V] = "z71v",
4888 [ALC880_6ST] = "6stack",
4889 [ALC880_6ST_DIG] = "6stack-digout",
4890 [ALC880_ASUS] = "asus",
4891 [ALC880_ASUS_W1V] = "asus-w1v",
4892 [ALC880_ASUS_DIG] = "asus-dig",
4893 [ALC880_ASUS_DIG2] = "asus-dig2",
4894 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004895 [ALC880_UNIWILL_P53] = "uniwill-p53",
4896 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004897 [ALC880_F1734] = "F1734",
4898 [ALC880_LG] = "lg",
4899 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004900 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004901#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004902 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004903#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004904 [ALC880_AUTO] = "auto",
4905};
4906
Takashi Iwaia9111322011-05-02 11:30:18 +02004907static const struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004908 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004909 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4910 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4911 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4912 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4913 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4914 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4915 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4916 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004917 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004918 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4919 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4920 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4921 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4922 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4923 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4924 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4925 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4926 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4927 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004928 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004929 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4930 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4931 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004932 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004933 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004934 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4935 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004936 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4937 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004938 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4939 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4940 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4941 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004942 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4943 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004944 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004945 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004946 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Justin P. Mattocka2e2bc22011-02-24 22:16:02 -08004947 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004948 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4949 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004950 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004951 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004952 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004953 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004954 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004955 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004956 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004957 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004958 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004959 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05004960 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004961 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004962 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004963 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4964 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4965 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4966 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004967 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4968 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004969 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004970 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004971 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4972 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004973 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4974 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4975 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004976 /* default Intel */
4977 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004978 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4979 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 {}
4981};
4982
Takashi Iwai16ded522005-06-10 19:58:24 +02004983/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004984 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004985 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004986static const struct alc_config_preset alc880_presets[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02004987 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004988 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004989 .init_verbs = { alc880_volume_init_verbs,
4990 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004991 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004992 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004993 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4994 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004995 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004996 .input_mux = &alc880_capture_source,
4997 },
4998 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004999 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005000 .init_verbs = { alc880_volume_init_verbs,
5001 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005002 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02005003 .dac_nids = alc880_dac_nids,
5004 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005005 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5006 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005007 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005008 .input_mux = &alc880_capture_source,
5009 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005010 [ALC880_TCL_S700] = {
5011 .mixers = { alc880_tcl_s700_mixer },
5012 .init_verbs = { alc880_volume_init_verbs,
5013 alc880_pin_tcl_S700_init_verbs,
5014 alc880_gpio2_init_verbs },
5015 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5016 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005017 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
5018 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01005019 .hp_nid = 0x03,
5020 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5021 .channel_mode = alc880_2_jack_modes,
5022 .input_mux = &alc880_capture_source,
5023 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005024 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005025 .mixers = { alc880_three_stack_mixer,
5026 alc880_five_stack_mixer},
5027 .init_verbs = { alc880_volume_init_verbs,
5028 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005029 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5030 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005031 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5032 .channel_mode = alc880_fivestack_modes,
5033 .input_mux = &alc880_capture_source,
5034 },
5035 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005036 .mixers = { alc880_three_stack_mixer,
5037 alc880_five_stack_mixer },
5038 .init_verbs = { alc880_volume_init_verbs,
5039 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005040 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5041 .dac_nids = alc880_dac_nids,
5042 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005043 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5044 .channel_mode = alc880_fivestack_modes,
5045 .input_mux = &alc880_capture_source,
5046 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005047 [ALC880_6ST] = {
5048 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005049 .init_verbs = { alc880_volume_init_verbs,
5050 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005051 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5052 .dac_nids = alc880_6st_dac_nids,
5053 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5054 .channel_mode = alc880_sixstack_modes,
5055 .input_mux = &alc880_6stack_capture_source,
5056 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005057 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005058 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005059 .init_verbs = { alc880_volume_init_verbs,
5060 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005061 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5062 .dac_nids = alc880_6st_dac_nids,
5063 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005064 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5065 .channel_mode = alc880_sixstack_modes,
5066 .input_mux = &alc880_6stack_capture_source,
5067 },
5068 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005069 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005070 .init_verbs = { alc880_volume_init_verbs,
5071 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005072 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005073 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
5074 .dac_nids = alc880_w810_dac_nids,
5075 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005076 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
5077 .channel_mode = alc880_w810_modes,
5078 .input_mux = &alc880_capture_source,
5079 },
5080 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005081 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005082 .init_verbs = { alc880_volume_init_verbs,
5083 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005084 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
5085 .dac_nids = alc880_z71v_dac_nids,
5086 .dig_out_nid = ALC880_DIGOUT_NID,
5087 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005088 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5089 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02005090 .input_mux = &alc880_capture_source,
5091 },
5092 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005093 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005094 .init_verbs = { alc880_volume_init_verbs,
5095 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005096 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
5097 .dac_nids = alc880_f1734_dac_nids,
5098 .hp_nid = 0x02,
5099 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5100 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01005101 .input_mux = &alc880_f1734_capture_source,
5102 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005103 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005104 .init_hook = alc_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02005105 },
5106 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005107 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005108 .init_verbs = { alc880_volume_init_verbs,
5109 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005110 alc880_gpio1_init_verbs },
5111 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5112 .dac_nids = alc880_asus_dac_nids,
5113 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5114 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005115 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005116 .input_mux = &alc880_capture_source,
5117 },
5118 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005119 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005120 .init_verbs = { alc880_volume_init_verbs,
5121 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005122 alc880_gpio1_init_verbs },
5123 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5124 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005125 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005126 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5127 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005128 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005129 .input_mux = &alc880_capture_source,
5130 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005131 [ALC880_ASUS_DIG2] = {
5132 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005133 .init_verbs = { alc880_volume_init_verbs,
5134 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01005135 alc880_gpio2_init_verbs }, /* use GPIO2 */
5136 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5137 .dac_nids = alc880_asus_dac_nids,
5138 .dig_out_nid = ALC880_DIGOUT_NID,
5139 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5140 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005141 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005142 .input_mux = &alc880_capture_source,
5143 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005144 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005145 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005146 .init_verbs = { alc880_volume_init_verbs,
5147 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005148 alc880_gpio1_init_verbs },
5149 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5150 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005151 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005152 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5153 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005154 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005155 .input_mux = &alc880_capture_source,
5156 },
5157 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005158 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02005159 .init_verbs = { alc880_volume_init_verbs,
5160 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005161 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5162 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005163 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005164 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5165 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005166 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005167 .input_mux = &alc880_capture_source,
5168 },
Kailang Yangccc656c2006-10-17 12:32:26 +02005169 [ALC880_UNIWILL] = {
5170 .mixers = { alc880_uniwill_mixer },
5171 .init_verbs = { alc880_volume_init_verbs,
5172 alc880_uniwill_init_verbs },
5173 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5174 .dac_nids = alc880_asus_dac_nids,
5175 .dig_out_nid = ALC880_DIGOUT_NID,
5176 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5177 .channel_mode = alc880_threestack_modes,
5178 .need_dac_fix = 1,
5179 .input_mux = &alc880_capture_source,
5180 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005181 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02005182 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02005183 },
5184 [ALC880_UNIWILL_P53] = {
5185 .mixers = { alc880_uniwill_p53_mixer },
5186 .init_verbs = { alc880_volume_init_verbs,
5187 alc880_uniwill_p53_init_verbs },
5188 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5189 .dac_nids = alc880_asus_dac_nids,
5190 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005191 .channel_mode = alc880_threestack_modes,
5192 .input_mux = &alc880_capture_source,
5193 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005194 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005195 .init_hook = alc_hp_automute,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005196 },
5197 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005198 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005199 .init_verbs = { alc880_volume_init_verbs,
5200 alc880_uniwill_p53_init_verbs,
5201 alc880_beep_init_verbs },
5202 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5203 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02005204 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005205 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5206 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02005207 .input_mux = &alc880_capture_source,
5208 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005209 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005210 .init_hook = alc_hp_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02005211 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005212 [ALC880_CLEVO] = {
5213 .mixers = { alc880_three_stack_mixer },
5214 .init_verbs = { alc880_volume_init_verbs,
5215 alc880_pin_clevo_init_verbs },
5216 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5217 .dac_nids = alc880_dac_nids,
5218 .hp_nid = 0x03,
5219 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5220 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005221 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005222 .input_mux = &alc880_capture_source,
5223 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005224 [ALC880_LG] = {
5225 .mixers = { alc880_lg_mixer },
5226 .init_verbs = { alc880_volume_init_verbs,
5227 alc880_lg_init_verbs },
5228 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
5229 .dac_nids = alc880_lg_dac_nids,
5230 .dig_out_nid = ALC880_DIGOUT_NID,
5231 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
5232 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005233 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005234 .input_mux = &alc880_lg_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005235 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005236 .setup = alc880_lg_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005237 .init_hook = alc_hp_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005238#ifdef CONFIG_SND_HDA_POWER_SAVE
5239 .loopbacks = alc880_lg_loopbacks,
5240#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005241 },
Takashi Iwaid6815182006-03-23 16:06:23 +01005242 [ALC880_LG_LW] = {
5243 .mixers = { alc880_lg_lw_mixer },
5244 .init_verbs = { alc880_volume_init_verbs,
5245 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005246 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01005247 .dac_nids = alc880_dac_nids,
5248 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005249 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
5250 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01005251 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005252 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005253 .setup = alc880_lg_lw_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005254 .init_hook = alc_hp_automute,
Takashi Iwaid6815182006-03-23 16:06:23 +01005255 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005256 [ALC880_MEDION_RIM] = {
5257 .mixers = { alc880_medion_rim_mixer },
5258 .init_verbs = { alc880_volume_init_verbs,
5259 alc880_medion_rim_init_verbs,
5260 alc_gpio2_init_verbs },
5261 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5262 .dac_nids = alc880_dac_nids,
5263 .dig_out_nid = ALC880_DIGOUT_NID,
5264 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5265 .channel_mode = alc880_2_jack_modes,
5266 .input_mux = &alc880_medion_rim_capture_source,
5267 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005268 .setup = alc880_medion_rim_setup,
5269 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005270 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005271#ifdef CONFIG_SND_DEBUG
5272 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005273 .mixers = { alc880_test_mixer },
5274 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005275 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
5276 .dac_nids = alc880_test_dac_nids,
5277 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005278 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
5279 .channel_mode = alc880_test_modes,
5280 .input_mux = &alc880_test_capture_source,
5281 },
5282#endif
5283};
5284
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005285/*
5286 * Automatic parse of I/O pins from the BIOS configuration
5287 */
5288
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005289enum {
5290 ALC_CTL_WIDGET_VOL,
5291 ALC_CTL_WIDGET_MUTE,
5292 ALC_CTL_BIND_MUTE,
5293};
Takashi Iwaia9111322011-05-02 11:30:18 +02005294static const struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005295 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
5296 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01005297 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005298};
5299
Takashi Iwaice764ab2011-04-27 16:35:23 +02005300static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
5301{
5302 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
5303 return snd_array_new(&spec->kctls);
5304}
5305
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005306/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005307static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005308 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005309{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005310 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005311
Takashi Iwaice764ab2011-04-27 16:35:23 +02005312 knew = alc_kcontrol_new(spec);
Takashi Iwai603c4012008-07-30 15:01:44 +02005313 if (!knew)
5314 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005315 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07005316 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005317 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005318 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005319 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01005320 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01005321 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005322 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005323 return 0;
5324}
5325
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005326static int add_control_with_pfx(struct alc_spec *spec, int type,
5327 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005328 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005329{
5330 char name[32];
5331 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005332 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005333}
5334
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005335#define add_pb_vol_ctrl(spec, type, pfx, val) \
5336 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5337#define add_pb_sw_ctrl(spec, type, pfx, val) \
5338 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5339#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5340 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5341#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5342 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005343
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005344#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5345#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5346#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5347#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005348#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5349#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5350#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5351#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5352#define ALC880_PIN_CD_NID 0x1c
5353
Takashi Iwai6843ca12011-06-24 11:03:58 +02005354static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
5355 bool can_be_master, int *index)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005356{
Takashi Iwaice764ab2011-04-27 16:35:23 +02005357 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai6843ca12011-06-24 11:03:58 +02005358 static const char * const chname[4] = {
5359 "Front", "Surround", NULL /*CLFE*/, "Side"
5360 };
Takashi Iwaice764ab2011-04-27 16:35:23 +02005361
Takashi Iwai6843ca12011-06-24 11:03:58 +02005362 *index = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02005363 if (cfg->line_outs == 1 && !spec->multi_ios &&
5364 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005365 return "Master";
5366
5367 switch (cfg->line_out_type) {
5368 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01005369 if (cfg->line_outs == 1)
5370 return "Speaker";
5371 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005372 case AUTO_PIN_HP_OUT:
Takashi Iwai6843ca12011-06-24 11:03:58 +02005373 /* for multi-io case, only the primary out */
5374 if (ch && spec->multi_ios)
5375 break;
5376 *index = ch;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005377 return "Headphone";
5378 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02005379 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005380 return "PCM";
5381 break;
5382 }
Takashi Iwai6843ca12011-06-24 11:03:58 +02005383 return chname[ch];
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005384}
5385
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005386/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005387static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005388 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005389 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005390{
Kailang Yangdf694da2005-12-05 19:42:22 +01005391 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005392
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005393 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005394 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5395 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005396 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005397 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005398 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5399 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005400 return err;
5401 return 0;
5402}
5403
Takashi Iwai05f5f472009-08-25 13:10:18 +02005404static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005405{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005406 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5407 return (pincap & AC_PINCAP_IN) != 0;
5408}
5409
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005410static int alc_auto_fill_adc_caps(struct hda_codec *codec)
Takashi Iwaib7821702011-07-06 15:12:46 +02005411{
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005412 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02005413 hda_nid_t nid;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005414 hda_nid_t *adc_nids = spec->private_adc_nids;
5415 hda_nid_t *cap_nids = spec->private_capsrc_nids;
5416 int max_nums = ARRAY_SIZE(spec->private_adc_nids);
5417 bool indep_capsrc = false;
Takashi Iwaib7821702011-07-06 15:12:46 +02005418 int i, nums = 0;
5419
5420 nid = codec->start_nid;
5421 for (i = 0; i < codec->num_nodes; i++, nid++) {
5422 hda_nid_t src;
5423 const hda_nid_t *list;
5424 unsigned int caps = get_wcaps(codec, nid);
5425 int type = get_wcaps_type(caps);
5426
5427 if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
5428 continue;
5429 adc_nids[nums] = nid;
5430 cap_nids[nums] = nid;
5431 src = nid;
5432 for (;;) {
5433 int n;
5434 type = get_wcaps_type(get_wcaps(codec, src));
5435 if (type == AC_WID_PIN)
5436 break;
5437 if (type == AC_WID_AUD_SEL) {
5438 cap_nids[nums] = src;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005439 indep_capsrc = true;
Takashi Iwaib7821702011-07-06 15:12:46 +02005440 break;
5441 }
5442 n = snd_hda_get_conn_list(codec, src, &list);
5443 if (n > 1) {
5444 cap_nids[nums] = src;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005445 indep_capsrc = true;
Takashi Iwaib7821702011-07-06 15:12:46 +02005446 break;
5447 } else if (n != 1)
5448 break;
5449 src = *list;
5450 }
5451 if (++nums >= max_nums)
5452 break;
5453 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005454 spec->adc_nids = spec->private_adc_nids;
5455 if (indep_capsrc)
5456 spec->capsrc_nids = spec->private_capsrc_nids;
5457 spec->num_adc_nids = nums;
Takashi Iwaib7821702011-07-06 15:12:46 +02005458 return nums;
5459}
5460
Takashi Iwai05f5f472009-08-25 13:10:18 +02005461/* create playback/capture controls for input pins */
Takashi Iwaib7821702011-07-06 15:12:46 +02005462static int alc_auto_create_input_ctls(struct hda_codec *codec)
Takashi Iwai05f5f472009-08-25 13:10:18 +02005463{
5464 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02005465 const struct auto_pin_cfg *cfg = &spec->autocfg;
5466 hda_nid_t mixer = spec->mixer_nid;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005467 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaib7821702011-07-06 15:12:46 +02005468 int num_adcs;
Takashi Iwaib7821702011-07-06 15:12:46 +02005469 int i, c, err, idx, type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005470 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005471
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005472 num_adcs = alc_auto_fill_adc_caps(codec);
Takashi Iwaib7821702011-07-06 15:12:46 +02005473 if (num_adcs < 0)
5474 return 0;
5475
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005476 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005477 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005478 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005479
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005480 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005481 if (!alc_is_input_pin(codec, pin))
5482 continue;
5483
David Henningsson5322bf22011-01-05 11:03:56 +01005484 label = hda_get_autocfg_input_label(codec, cfg, i);
5485 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005486 type_idx++;
5487 else
5488 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005489 prev_label = label;
5490
Takashi Iwai05f5f472009-08-25 13:10:18 +02005491 if (mixer) {
5492 idx = get_connection_index(codec, mixer, pin);
5493 if (idx >= 0) {
5494 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005495 label, type_idx,
5496 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005497 if (err < 0)
5498 return err;
5499 }
5500 }
5501
Takashi Iwaib7821702011-07-06 15:12:46 +02005502 for (c = 0; c < num_adcs; c++) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005503 hda_nid_t cap = spec->capsrc_nids ?
5504 spec->capsrc_nids[c] : spec->adc_nids[c];
5505 idx = get_connection_index(codec, cap, pin);
Takashi Iwaib7821702011-07-06 15:12:46 +02005506 if (idx >= 0) {
5507 snd_hda_add_imux_item(imux, label, idx, NULL);
5508 break;
5509 }
5510 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005511 }
5512 return 0;
5513}
5514
Takashi Iwai343a04b2011-07-06 14:28:39 +02005515static int alc_auto_fill_dac_nids(struct hda_codec *codec);
5516static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
5517 const struct auto_pin_cfg *cfg);
5518static int alc_auto_create_hp_out(struct hda_codec *codec);
5519static int alc_auto_create_speaker_out(struct hda_codec *codec);
5520static void alc_auto_init_multi_out(struct hda_codec *codec);
5521static void alc_auto_init_extra_out(struct hda_codec *codec);
5522
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005523static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5524 unsigned int pin_type)
5525{
5526 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5527 pin_type);
5528 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005529 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5530 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005531}
5532
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005533static int get_pin_type(int line_out_type)
5534{
5535 if (line_out_type == AUTO_PIN_HP_OUT)
5536 return PIN_HP;
5537 else
5538 return PIN_OUT;
5539}
5540
Takashi Iwai0a7f5322011-07-06 15:15:12 +02005541static void alc_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005542{
5543 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005544 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005545 int i;
5546
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005547 for (i = 0; i < cfg->num_inputs; i++) {
5548 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005549 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005550 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005551 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005552 snd_hda_codec_write(codec, nid, 0,
5553 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005554 AMP_OUT_MUTE);
5555 }
5556 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005557
5558 /* mute all loopback inputs */
5559 if (spec->mixer_nid) {
5560 int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
5561 for (i = 0; i < nums; i++)
5562 snd_hda_codec_write(codec, spec->mixer_nid, 0,
5563 AC_VERB_SET_AMP_GAIN_MUTE,
5564 AMP_IN_MUTE(i));
5565 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005566}
5567
Takashi Iwaicb053a82011-06-27 11:32:07 +02005568static int alc_auto_add_multi_channel_mode(struct hda_codec *codec,
5569 int (*fill_dac)(struct hda_codec *));
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005570static void alc_remove_invalid_adc_nids(struct hda_codec *codec);
Takashi Iwaif970de22011-07-06 17:39:59 +02005571static void alc_auto_init_input_src(struct hda_codec *codec);
Takashi Iwaice764ab2011-04-27 16:35:23 +02005572
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005573/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005574/* return 1 if successful, 0 if the proper config is not found,
5575 * or a negative error code
5576 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005577static int alc880_parse_auto_config(struct hda_codec *codec)
5578{
5579 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005580 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005581 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005582
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005583 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5584 alc880_ignore);
5585 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005586 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005587 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005588 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005589
Takashi Iwai343a04b2011-07-06 14:28:39 +02005590 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005591 if (err < 0)
5592 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005593 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +02005594 if (err < 0)
5595 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005596 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005597 if (err < 0)
5598 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005599 err = alc_auto_create_hp_out(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005600 if (err < 0)
5601 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005602 err = alc_auto_create_speaker_out(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005603 if (err < 0)
5604 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +02005605 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005606 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005607 return err;
5608
5609 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5610
Takashi Iwai757899a2010-07-30 10:48:14 +02005611 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005612
Takashi Iwai603c4012008-07-30 15:01:44 +02005613 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005614 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005615
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005616 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005617 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005618
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005619 if (!spec->dual_adc_switch)
5620 alc_remove_invalid_adc_nids(codec);
5621
Kailang Yang6227cdc2010-02-25 08:36:52 +01005622 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005623
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005624 return 1;
5625}
5626
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005627/* additional initialization for auto-configuration model */
5628static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005629{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005630 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005631 alc_auto_init_multi_out(codec);
5632 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +02005633 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +02005634 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005635 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005636 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005637 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005638}
5639
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005640/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5641 * one of two digital mic pins, e.g. on ALC272
5642 */
5643static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005644{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005645 struct alc_spec *spec = codec->spec;
5646 int i;
5647
5648 for (i = 0; i < spec->num_adc_nids; i++) {
5649 hda_nid_t cap = spec->capsrc_nids ?
5650 spec->capsrc_nids[i] : spec->adc_nids[i];
5651 int iidx, eidx;
5652
5653 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5654 if (iidx < 0)
5655 continue;
5656 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5657 if (eidx < 0)
5658 continue;
5659 spec->int_mic.mux_idx = iidx;
5660 spec->ext_mic.mux_idx = eidx;
5661 if (spec->capsrc_nids)
5662 spec->capsrc_nids += i;
5663 spec->adc_nids += i;
5664 spec->num_adc_nids = 1;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005665 /* optional dock-mic */
5666 eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
5667 if (eidx < 0)
5668 spec->dock_mic.pin = 0;
5669 else
5670 spec->dock_mic.mux_idx = eidx;
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005671 return;
5672 }
5673 snd_printd(KERN_INFO "hda_codec: %s: "
5674 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5675 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5676 spec->auto_mic = 0; /* disable auto-mic to be sure */
5677}
5678
Takashi Iwai748cce42010-08-04 07:37:39 +02005679/* select or unmute the given capsrc route */
5680static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5681 int idx)
5682{
5683 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5684 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5685 HDA_AMP_MUTE, 0);
5686 } else {
5687 snd_hda_codec_write_cache(codec, cap, 0,
5688 AC_VERB_SET_CONNECT_SEL, idx);
5689 }
5690}
5691
Takashi Iwai840b64c2010-07-13 22:49:01 +02005692/* set the default connection to that pin */
5693static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5694{
5695 struct alc_spec *spec = codec->spec;
5696 int i;
5697
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005698 if (!pin)
5699 return 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005700 for (i = 0; i < spec->num_adc_nids; i++) {
5701 hda_nid_t cap = spec->capsrc_nids ?
5702 spec->capsrc_nids[i] : spec->adc_nids[i];
5703 int idx;
5704
5705 idx = get_connection_index(codec, cap, pin);
5706 if (idx < 0)
5707 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005708 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005709 return i; /* return the found index */
5710 }
5711 return -1; /* not found */
5712}
5713
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005714/* choose the ADC/MUX containing the input pin and initialize the setup */
5715static void fixup_single_adc(struct hda_codec *codec)
5716{
5717 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005718 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005719 int i;
5720
5721 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005722 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005723 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005724 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005725 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005726 /* use only this ADC */
5727 if (spec->capsrc_nids)
5728 spec->capsrc_nids += i;
5729 spec->adc_nids += i;
5730 spec->num_adc_nids = 1;
Takashi Iwai584c0c42011-03-10 12:51:11 +01005731 spec->single_input_src = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005732 }
5733}
5734
Takashi Iwai840b64c2010-07-13 22:49:01 +02005735/* initialize dual adcs */
5736static void fixup_dual_adc_switch(struct hda_codec *codec)
5737{
5738 struct alc_spec *spec = codec->spec;
5739 init_capsrc_for_pin(codec, spec->ext_mic.pin);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005740 init_capsrc_for_pin(codec, spec->dock_mic.pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005741 init_capsrc_for_pin(codec, spec->int_mic.pin);
5742}
5743
Takashi Iwai584c0c42011-03-10 12:51:11 +01005744/* initialize some special cases for input sources */
5745static void alc_init_special_input_src(struct hda_codec *codec)
5746{
5747 struct alc_spec *spec = codec->spec;
5748 if (spec->dual_adc_switch)
5749 fixup_dual_adc_switch(codec);
5750 else if (spec->single_input_src)
5751 init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
5752}
5753
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005754static void set_capture_mixer(struct hda_codec *codec)
5755{
5756 struct alc_spec *spec = codec->spec;
Takashi Iwaia9111322011-05-02 11:30:18 +02005757 static const struct snd_kcontrol_new *caps[2][3] = {
Takashi Iwaia23b6882009-03-23 15:21:36 +01005758 { alc_capture_mixer_nosrc1,
5759 alc_capture_mixer_nosrc2,
5760 alc_capture_mixer_nosrc3 },
5761 { alc_capture_mixer1,
5762 alc_capture_mixer2,
5763 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005764 };
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005765
5766 /* check whether either of ADC or MUX has a volume control */
5767 if (!(query_amp_caps(codec, spec->adc_nids[0], HDA_INPUT) &
5768 AC_AMPCAP_NUM_STEPS)) {
5769 if (!spec->capsrc_nids)
5770 return; /* no volume */
5771 if (!(query_amp_caps(codec, spec->capsrc_nids[0], HDA_OUTPUT) &
5772 AC_AMPCAP_NUM_STEPS))
5773 return; /* no volume in capsrc, too */
5774 spec->vol_in_capsrc = 1;
5775 }
5776
5777 if (spec->num_adc_nids > 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005778 int mux = 0;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005779 int num_adcs = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005780 if (spec->dual_adc_switch)
Takashi Iwai584c0c42011-03-10 12:51:11 +01005781 num_adcs = 1;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005782 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005783 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005784 else if (spec->input_mux) {
5785 if (spec->input_mux->num_items > 1)
5786 mux = 1;
5787 else if (spec->input_mux->num_items == 1)
5788 fixup_single_adc(codec);
5789 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005790 if (!num_adcs) {
5791 if (spec->num_adc_nids > 3)
5792 spec->num_adc_nids = 3;
5793 else if (!spec->num_adc_nids)
5794 return;
5795 num_adcs = spec->num_adc_nids;
5796 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005797 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005798 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005799}
5800
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005801/* filter out invalid adc_nids (and capsrc_nids) that don't give all
5802 * active input pins
5803 */
5804static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
Takashi Iwai66946352010-03-29 17:21:45 +02005805{
5806 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005807 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005808 hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
5809 hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
5810 int i, n, nums;
Takashi Iwai66946352010-03-29 17:21:45 +02005811
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005812 nums = 0;
5813 for (n = 0; n < spec->num_adc_nids; n++) {
5814 hda_nid_t cap = spec->private_capsrc_nids[n];
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005815 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005816 hda_nid_t pin = cfg->inputs[i].pin;
5817 if (get_connection_index(codec, cap, pin) < 0)
Takashi Iwai66946352010-03-29 17:21:45 +02005818 break;
5819 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005820 if (i >= cfg->num_inputs) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005821 adc_nids[nums] = spec->private_adc_nids[n];
5822 capsrc_nids[nums++] = cap;
Takashi Iwai66946352010-03-29 17:21:45 +02005823 }
5824 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005825 if (!nums) {
Takashi Iwai66946352010-03-29 17:21:45 +02005826 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005827 " using fallback 0x%x\n",
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005828 codec->chip_name, spec->private_adc_nids[0]);
5829 spec->num_adc_nids = 1;
5830 } else if (nums != spec->num_adc_nids) {
5831 memcpy(spec->private_adc_nids, adc_nids,
5832 nums * sizeof(hda_nid_t));
5833 memcpy(spec->private_capsrc_nids, capsrc_nids,
5834 nums * sizeof(hda_nid_t));
5835 spec->num_adc_nids = nums;
Takashi Iwai66946352010-03-29 17:21:45 +02005836 }
5837}
5838
Takashi Iwai67d634c2009-11-16 15:35:59 +01005839#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005840#define set_beep_amp(spec, nid, idx, dir) \
5841 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005842
Takashi Iwaia9111322011-05-02 11:30:18 +02005843static const struct snd_pci_quirk beep_white_list[] = {
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005844 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005845 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Daniel Corderoa7e985e2011-04-29 08:18:06 +02005846 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
Madis Janson39dfe132011-05-19 18:32:41 +02005847 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005848 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005849 {}
5850};
5851
5852static inline int has_cdefine_beep(struct hda_codec *codec)
5853{
5854 struct alc_spec *spec = codec->spec;
5855 const struct snd_pci_quirk *q;
5856 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5857 if (q)
5858 return q->value;
5859 return spec->cdefine.enable_pcbeep;
5860}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005861#else
5862#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005863#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005864#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005865
5866/*
5867 * OK, here we have finally the patch for ALC880
5868 */
5869
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870static int patch_alc880(struct hda_codec *codec)
5871{
5872 struct alc_spec *spec;
5873 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005874 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005876 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877 if (spec == NULL)
5878 return -ENOMEM;
5879
5880 codec->spec = spec;
5881
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005882 spec->mixer_nid = 0x0b;
5883
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005884 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5885 alc880_models,
5886 alc880_cfg_tbl);
5887 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005888 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5889 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005890 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 }
5892
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005893 if (board_config == ALC880_AUTO) {
5894 /* automatic parse from the BIOS config */
5895 err = alc880_parse_auto_config(codec);
5896 if (err < 0) {
5897 alc_free(codec);
5898 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005899 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005900 printk(KERN_INFO
5901 "hda_codec: Cannot set up configuration "
5902 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005903 board_config = ALC880_3ST;
5904 }
5905 }
5906
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005907 err = snd_hda_attach_beep_device(codec, 0x1);
5908 if (err < 0) {
5909 alc_free(codec);
5910 return err;
5911 }
5912
Kailang Yangdf694da2005-12-05 19:42:22 +01005913 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005914 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005916 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005917 alc_auto_fill_adc_caps(codec);
5918 alc_remove_invalid_adc_nids(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005919 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005920 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005921 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
Takashi Iwai2134ea42008-01-10 16:53:55 +01005923 spec->vmaster_nid = 0x0c;
5924
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005926 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005927 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005928#ifdef CONFIG_SND_HDA_POWER_SAVE
5929 if (!spec->loopback.amplist)
5930 spec->loopback.amplist = alc880_loopbacks;
5931#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932
5933 return 0;
5934}
5935
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005936
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937/*
5938 * ALC260 support
5939 */
5940
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005941static const hda_nid_t alc260_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005942 /* front */
5943 0x02,
5944};
5945
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005946static const hda_nid_t alc260_adc_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005947 /* ADC0 */
5948 0x04,
5949};
5950
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005951static const hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005952 /* ADC1 */
5953 0x05,
5954};
5955
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005956/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5957 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5958 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005959static const hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005960 /* ADC0, ADC1 */
5961 0x04, 0x05
5962};
5963
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005964#define ALC260_DIGOUT_NID 0x03
5965#define ALC260_DIGIN_NID 0x06
5966
Takashi Iwaia9111322011-05-02 11:30:18 +02005967static const struct hda_input_mux alc260_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005968 .num_items = 4,
5969 .items = {
5970 { "Mic", 0x0 },
5971 { "Front Mic", 0x1 },
5972 { "Line", 0x2 },
5973 { "CD", 0x4 },
5974 },
5975};
5976
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005977/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005978 * headphone jack and the internal CD lines since these are the only pins at
5979 * which audio can appear. For flexibility, also allow the option of
5980 * recording the mixer output on the second ADC (ADC0 doesn't have a
5981 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005982 */
Takashi Iwaia9111322011-05-02 11:30:18 +02005983static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005984 {
5985 .num_items = 3,
5986 .items = {
5987 { "Mic/Line", 0x0 },
5988 { "CD", 0x4 },
5989 { "Headphone", 0x2 },
5990 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005991 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005992 {
5993 .num_items = 4,
5994 .items = {
5995 { "Mic/Line", 0x0 },
5996 { "CD", 0x4 },
5997 { "Headphone", 0x2 },
5998 { "Mixer", 0x5 },
5999 },
6000 },
6001
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006002};
6003
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006004/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
6005 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006006 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006007static const struct hda_input_mux alc260_acer_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006008 {
6009 .num_items = 4,
6010 .items = {
6011 { "Mic", 0x0 },
6012 { "Line", 0x2 },
6013 { "CD", 0x4 },
6014 { "Headphone", 0x5 },
6015 },
6016 },
6017 {
6018 .num_items = 5,
6019 .items = {
6020 { "Mic", 0x0 },
6021 { "Line", 0x2 },
6022 { "CD", 0x4 },
6023 { "Headphone", 0x6 },
6024 { "Mixer", 0x5 },
6025 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006026 },
6027};
Michael Schwingencc959482009-02-22 18:58:45 +01006028
6029/* Maxdata Favorit 100XS */
Takashi Iwaia9111322011-05-02 11:30:18 +02006030static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006031 {
6032 .num_items = 2,
6033 .items = {
6034 { "Line/Mic", 0x0 },
6035 { "CD", 0x4 },
6036 },
6037 },
6038 {
6039 .num_items = 3,
6040 .items = {
6041 { "Line/Mic", 0x0 },
6042 { "CD", 0x4 },
6043 { "Mixer", 0x5 },
6044 },
6045 },
6046};
6047
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048/*
6049 * This is just place-holder, so there's something for alc_build_pcms to look
6050 * at when it calculates the maximum number of channels. ALC260 has no mixer
6051 * element which allows changing the channel mode, so the verb list is
6052 * never used.
6053 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006054static const struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055 { 2, NULL },
6056};
6057
Kailang Yangdf694da2005-12-05 19:42:22 +01006058
6059/* Mixer combinations
6060 *
6061 * basic: base_output + input + pc_beep + capture
6062 * HP: base_output + input + capture_alt
6063 * HP_3013: hp_3013 + input + capture
6064 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006065 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01006066 */
6067
Takashi Iwaia9111322011-05-02 11:30:18 +02006068static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006069 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006070 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006071 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6072 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6073 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6074 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6075 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006076};
Kailang Yangdf694da2005-12-05 19:42:22 +01006077
Takashi Iwaia9111322011-05-02 11:30:18 +02006078static const struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6080 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6081 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6082 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6083 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6084 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6085 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
6086 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 { } /* end */
6088};
6089
Takashi Iwaibec15c32008-01-28 18:16:30 +01006090/* update HP, line and mono out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +02006091static void alc260_hp_master_update(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006092{
Takashi Iwaie9427962011-04-28 15:46:07 +02006093 update_speakers(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006094}
6095
6096static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
6097 struct snd_ctl_elem_value *ucontrol)
6098{
6099 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6100 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006101 *ucontrol->value.integer.value = !spec->master_mute;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006102 return 0;
6103}
6104
6105static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
6106 struct snd_ctl_elem_value *ucontrol)
6107{
6108 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6109 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006110 int val = !*ucontrol->value.integer.value;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006111
Takashi Iwaie9427962011-04-28 15:46:07 +02006112 if (val == spec->master_mute)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006113 return 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02006114 spec->master_mute = val;
6115 alc260_hp_master_update(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006116 return 1;
6117}
6118
Takashi Iwaia9111322011-05-02 11:30:18 +02006119static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006120 {
6121 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6122 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006123 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006124 .info = snd_ctl_boolean_mono_info,
6125 .get = alc260_hp_master_sw_get,
6126 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006127 },
6128 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6129 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
6130 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6131 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6132 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
6133 HDA_OUTPUT),
6134 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6135 { } /* end */
6136};
6137
Takashi Iwaia9111322011-05-02 11:30:18 +02006138static const struct hda_verb alc260_hp_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006139 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6140 {},
6141};
6142
Takashi Iwaie9427962011-04-28 15:46:07 +02006143static void alc260_hp_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006144{
6145 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006146
Takashi Iwaie9427962011-04-28 15:46:07 +02006147 spec->autocfg.hp_pins[0] = 0x0f;
6148 spec->autocfg.speaker_pins[0] = 0x10;
6149 spec->autocfg.speaker_pins[1] = 0x11;
6150 spec->automute = 1;
6151 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006152}
6153
Takashi Iwaia9111322011-05-02 11:30:18 +02006154static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006155 {
6156 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6157 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006158 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006159 .info = snd_ctl_boolean_mono_info,
6160 .get = alc260_hp_master_sw_get,
6161 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006162 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006163 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6164 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6165 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
6166 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
6167 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6168 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006169 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6170 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02006171 { } /* end */
6172};
6173
Takashi Iwaie9427962011-04-28 15:46:07 +02006174static void alc260_hp_3013_setup(struct hda_codec *codec)
6175{
6176 struct alc_spec *spec = codec->spec;
6177
6178 spec->autocfg.hp_pins[0] = 0x15;
6179 spec->autocfg.speaker_pins[0] = 0x10;
6180 spec->autocfg.speaker_pins[1] = 0x11;
6181 spec->automute = 1;
6182 spec->automute_mode = ALC_AUTOMUTE_PIN;
6183}
6184
Takashi Iwaia9111322011-05-02 11:30:18 +02006185static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
Kailang Yang3f878302008-08-26 13:02:23 +02006186 .ops = &snd_hda_bind_vol,
6187 .values = {
6188 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
6189 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
6190 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
6191 0
6192 },
6193};
6194
Takashi Iwaia9111322011-05-02 11:30:18 +02006195static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
Kailang Yang3f878302008-08-26 13:02:23 +02006196 .ops = &snd_hda_bind_sw,
6197 .values = {
6198 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
6199 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
6200 0
6201 },
6202};
6203
Takashi Iwaia9111322011-05-02 11:30:18 +02006204static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006205 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
6206 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
6207 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
6208 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6209 { } /* end */
6210};
6211
Takashi Iwaia9111322011-05-02 11:30:18 +02006212static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006213 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6214 {},
6215};
6216
Takashi Iwaie9427962011-04-28 15:46:07 +02006217static void alc260_hp_3012_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006218{
6219 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006220
Takashi Iwaie9427962011-04-28 15:46:07 +02006221 spec->autocfg.hp_pins[0] = 0x10;
6222 spec->autocfg.speaker_pins[0] = 0x0f;
6223 spec->autocfg.speaker_pins[1] = 0x11;
6224 spec->autocfg.speaker_pins[2] = 0x15;
6225 spec->automute = 1;
6226 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang3f878302008-08-26 13:02:23 +02006227}
6228
6229/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006230 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6231 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006232static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006233 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006234 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006235 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006236 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6237 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6238 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6239 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006240 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006241 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6242 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006243 { } /* end */
6244};
6245
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006246/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6247 * versions of the ALC260 don't act on requests to enable mic bias from NID
6248 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6249 * datasheet doesn't mention this restriction. At this stage it's not clear
6250 * whether this behaviour is intentional or is a hardware bug in chip
6251 * revisions available in early 2006. Therefore for now allow the
6252 * "Headphone Jack Mode" control to span all choices, but if it turns out
6253 * that the lack of mic bias for this NID is intentional we could change the
6254 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6255 *
6256 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6257 * don't appear to make the mic bias available from the "line" jack, even
6258 * though the NID used for this jack (0x14) can supply it. The theory is
6259 * that perhaps Acer have included blocking capacitors between the ALC260
6260 * and the output jack. If this turns out to be the case for all such
6261 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6262 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006263 *
6264 * The C20x Tablet series have a mono internal speaker which is controlled
6265 * via the chip's Mono sum widget and pin complex, so include the necessary
6266 * controls for such models. On models without a "mono speaker" the control
6267 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006268 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006269static const struct snd_kcontrol_new alc260_acer_mixer[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006270 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6271 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006272 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006273 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006274 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006275 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006276 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006277 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6278 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6279 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6280 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6281 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6282 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6283 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6284 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006285 { } /* end */
6286};
6287
Michael Schwingencc959482009-02-22 18:58:45 +01006288/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6289 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006290static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006291 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6292 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6293 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6294 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6295 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6296 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6297 { } /* end */
6298};
6299
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006300/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6301 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6302 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006303static const struct snd_kcontrol_new alc260_will_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006304 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6305 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6306 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6307 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6308 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6309 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6310 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6311 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6312 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6313 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006314 { } /* end */
6315};
6316
6317/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6318 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6319 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006320static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006321 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6322 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6323 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6324 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6325 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6326 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6327 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6328 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6329 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6330 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6331 { } /* end */
6332};
6333
Kailang Yangdf694da2005-12-05 19:42:22 +01006334/*
6335 * initialization verbs
6336 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006337static const struct hda_verb alc260_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006339 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006341 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006343 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006345 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006347 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006349 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006351 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006353 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006355 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6356 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006357 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 /* set connection select to line in (default select for this ADC) */
6359 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006360 /* mute capture amp left and right */
6361 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6362 /* set connection select to line in (default select for this ADC) */
6363 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006364 /* set vol=0 Line-Out mixer amp left and right */
6365 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6366 /* unmute pin widget amp left and right (no gain on this amp) */
6367 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6368 /* set vol=0 HP mixer amp left and right */
6369 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6370 /* unmute pin widget amp left and right (no gain on this amp) */
6371 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6372 /* set vol=0 Mono mixer amp left and right */
6373 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6374 /* unmute pin widget amp left and right (no gain on this amp) */
6375 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6376 /* unmute LINE-2 out pin */
6377 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006378 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6379 * Line In 2 = 0x03
6380 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006381 /* mute analog inputs */
6382 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6383 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6384 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6385 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6386 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006388 /* mute Front out path */
6389 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6390 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6391 /* mute Headphone out path */
6392 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6393 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6394 /* mute Mono out path */
6395 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6396 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 { }
6398};
6399
Takashi Iwai474167d2006-05-17 17:17:43 +02006400#if 0 /* should be identical with alc260_init_verbs? */
Takashi Iwaia9111322011-05-02 11:30:18 +02006401static const struct hda_verb alc260_hp_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006402 /* Headphone and output */
6403 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6404 /* mono output */
6405 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6406 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6407 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6408 /* Mic2 (front panel) pin widget for input and vref at 80% */
6409 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6410 /* Line In pin widget for input */
6411 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6412 /* Line-2 pin widget for output */
6413 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6414 /* CD pin widget for input */
6415 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6416 /* unmute amp left and right */
6417 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6418 /* set connection select to line in (default select for this ADC) */
6419 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6420 /* unmute Line-Out mixer amp left and right (volume = 0) */
6421 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6422 /* mute pin widget amp left and right (no gain on this amp) */
6423 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6424 /* unmute HP mixer amp left and right (volume = 0) */
6425 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6426 /* mute pin widget amp left and right (no gain on this amp) */
6427 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006428 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6429 * Line In 2 = 0x03
6430 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006431 /* mute analog inputs */
6432 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6433 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6434 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6435 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6436 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006437 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6438 /* Unmute Front out path */
6439 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6440 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6441 /* Unmute Headphone out path */
6442 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6443 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6444 /* Unmute Mono out path */
6445 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6446 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6447 { }
6448};
Takashi Iwai474167d2006-05-17 17:17:43 +02006449#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006450
Takashi Iwaia9111322011-05-02 11:30:18 +02006451static const struct hda_verb alc260_hp_3013_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006452 /* Line out and output */
6453 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6454 /* mono output */
6455 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6456 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6457 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6458 /* Mic2 (front panel) pin widget for input and vref at 80% */
6459 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6460 /* Line In pin widget for input */
6461 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6462 /* Headphone pin widget for output */
6463 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6464 /* CD pin widget for input */
6465 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6466 /* unmute amp left and right */
6467 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6468 /* set connection select to line in (default select for this ADC) */
6469 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6470 /* unmute Line-Out mixer amp left and right (volume = 0) */
6471 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6472 /* mute pin widget amp left and right (no gain on this amp) */
6473 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6474 /* unmute HP mixer amp left and right (volume = 0) */
6475 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6476 /* mute pin widget amp left and right (no gain on this amp) */
6477 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006478 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6479 * Line In 2 = 0x03
6480 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006481 /* mute analog inputs */
6482 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6483 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6484 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6485 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6486 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006487 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6488 /* Unmute Front out path */
6489 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6490 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6491 /* Unmute Headphone out path */
6492 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6493 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6494 /* Unmute Mono out path */
6495 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6496 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6497 { }
6498};
6499
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006500/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006501 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6502 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006503 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006504static const struct hda_verb alc260_fujitsu_init_verbs[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006505 /* Disable all GPIOs */
6506 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6507 /* Internal speaker is connected to headphone pin */
6508 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6509 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6510 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006511 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6512 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6513 /* Ensure all other unused pins are disabled and muted. */
6514 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6515 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006516 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006517 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006518 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006519 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6520 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6521 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006522
Jonathan Woithef7ace402006-02-28 11:46:14 +01006523 /* Disable digital (SPDIF) pins */
6524 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6525 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006526
Kailang Yangea1fb292008-08-26 12:58:38 +02006527 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006528 * when acting as an output.
6529 */
6530 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6531
6532 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006533 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6534 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6535 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6536 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6537 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6538 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6539 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6540 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6541 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006542
Jonathan Woithef7ace402006-02-28 11:46:14 +01006543 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6544 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6545 /* Unmute Line1 pin widget output buffer since it starts as an output.
6546 * If the pin mode is changed by the user the pin mode control will
6547 * take care of enabling the pin's input/output buffers as needed.
6548 * Therefore there's no need to enable the input buffer at this
6549 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006550 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006551 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006552 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006553 * mixer ctrl)
6554 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006555 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006556
Jonathan Woithef7ace402006-02-28 11:46:14 +01006557 /* Mute capture amp left and right */
6558 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006559 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006560 * in (on mic1 pin)
6561 */
6562 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006563
Jonathan Woithef7ace402006-02-28 11:46:14 +01006564 /* Do the same for the second ADC: mute capture input amp and
6565 * set ADC connection to line in (on mic1 pin)
6566 */
6567 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6568 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006569
Jonathan Woithef7ace402006-02-28 11:46:14 +01006570 /* Mute all inputs to mixer widget (even unconnected ones) */
6571 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6572 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6573 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6574 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6575 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6576 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6577 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6578 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006579
6580 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006581};
6582
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006583/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6584 * similar laptops (adapted from Fujitsu init verbs).
6585 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006586static const struct hda_verb alc260_acer_init_verbs[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006587 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6588 * the headphone jack. Turn this on and rely on the standard mute
6589 * methods whenever the user wants to turn these outputs off.
6590 */
6591 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6592 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6593 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6594 /* Internal speaker/Headphone jack is connected to Line-out pin */
6595 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6596 /* Internal microphone/Mic jack is connected to Mic1 pin */
6597 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6598 /* Line In jack is connected to Line1 pin */
6599 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006600 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6601 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006602 /* Ensure all other unused pins are disabled and muted. */
6603 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6604 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006605 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6606 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6607 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6608 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6609 /* Disable digital (SPDIF) pins */
6610 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6611 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6612
Kailang Yangea1fb292008-08-26 12:58:38 +02006613 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006614 * bus when acting as outputs.
6615 */
6616 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6617 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6618
6619 /* Start with output sum widgets muted and their output gains at min */
6620 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6621 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6622 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6623 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6624 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6625 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6626 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6627 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6628 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6629
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006630 /* Unmute Line-out pin widget amp left and right
6631 * (no equiv mixer ctrl)
6632 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006633 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006634 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6635 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006636 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6637 * inputs. If the pin mode is changed by the user the pin mode control
6638 * will take care of enabling the pin's input/output buffers as needed.
6639 * Therefore there's no need to enable the input buffer at this
6640 * stage.
6641 */
6642 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6643 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6644
6645 /* Mute capture amp left and right */
6646 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6647 /* Set ADC connection select to match default mixer setting - mic
6648 * (on mic1 pin)
6649 */
6650 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6651
6652 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006653 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006654 */
6655 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006656 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006657
6658 /* Mute all inputs to mixer widget (even unconnected ones) */
6659 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6660 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6661 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6662 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6663 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6664 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6665 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6666 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6667
6668 { }
6669};
6670
Michael Schwingencc959482009-02-22 18:58:45 +01006671/* Initialisation sequence for Maxdata Favorit 100XS
6672 * (adapted from Acer init verbs).
6673 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006674static const struct hda_verb alc260_favorit100_init_verbs[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006675 /* GPIO 0 enables the output jack.
6676 * Turn this on and rely on the standard mute
6677 * methods whenever the user wants to turn these outputs off.
6678 */
6679 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6680 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6681 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6682 /* Line/Mic input jack is connected to Mic1 pin */
6683 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6684 /* Ensure all other unused pins are disabled and muted. */
6685 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6686 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6687 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6688 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6689 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6690 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6691 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6692 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6693 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6694 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6695 /* Disable digital (SPDIF) pins */
6696 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6697 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6698
6699 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6700 * bus when acting as outputs.
6701 */
6702 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6703 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6704
6705 /* Start with output sum widgets muted and their output gains at min */
6706 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6707 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6708 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6709 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6710 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6711 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6712 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6713 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6714 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6715
6716 /* Unmute Line-out pin widget amp left and right
6717 * (no equiv mixer ctrl)
6718 */
6719 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6720 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6721 * inputs. If the pin mode is changed by the user the pin mode control
6722 * will take care of enabling the pin's input/output buffers as needed.
6723 * Therefore there's no need to enable the input buffer at this
6724 * stage.
6725 */
6726 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6727
6728 /* Mute capture amp left and right */
6729 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6730 /* Set ADC connection select to match default mixer setting - mic
6731 * (on mic1 pin)
6732 */
6733 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6734
6735 /* Do similar with the second ADC: mute capture input amp and
6736 * set ADC connection to mic to match ALSA's default state.
6737 */
6738 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6739 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6740
6741 /* Mute all inputs to mixer widget (even unconnected ones) */
6742 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6743 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6744 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6745 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6746 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6747 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6748 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6749 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6750
6751 { }
6752};
6753
Takashi Iwaia9111322011-05-02 11:30:18 +02006754static const struct hda_verb alc260_will_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006755 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6756 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6757 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6758 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6759 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6760 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6761 {}
6762};
6763
Takashi Iwaia9111322011-05-02 11:30:18 +02006764static const struct hda_verb alc260_replacer_672v_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006765 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6766 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6767 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6768
6769 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6770 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6771 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6772
6773 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6774 {}
6775};
6776
6777/* toggle speaker-output according to the hp-jack state */
6778static void alc260_replacer_672v_automute(struct hda_codec *codec)
6779{
6780 unsigned int present;
6781
6782 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006783 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006784 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006785 snd_hda_codec_write_cache(codec, 0x01, 0,
6786 AC_VERB_SET_GPIO_DATA, 1);
6787 snd_hda_codec_write_cache(codec, 0x0f, 0,
6788 AC_VERB_SET_PIN_WIDGET_CONTROL,
6789 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006790 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006791 snd_hda_codec_write_cache(codec, 0x01, 0,
6792 AC_VERB_SET_GPIO_DATA, 0);
6793 snd_hda_codec_write_cache(codec, 0x0f, 0,
6794 AC_VERB_SET_PIN_WIDGET_CONTROL,
6795 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006796 }
6797}
6798
6799static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6800 unsigned int res)
6801{
6802 if ((res >> 26) == ALC880_HP_EVENT)
6803 alc260_replacer_672v_automute(codec);
6804}
6805
Takashi Iwaia9111322011-05-02 11:30:18 +02006806static const struct hda_verb alc260_hp_dc7600_verbs[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006807 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6808 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6809 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6810 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6811 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6812 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6813 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6814 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6815 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6816 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6817 {}
6818};
6819
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006820/* Test configuration for debugging, modelled after the ALC880 test
6821 * configuration.
6822 */
6823#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006824static const hda_nid_t alc260_test_dac_nids[1] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006825 0x02,
6826};
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006827static const hda_nid_t alc260_test_adc_nids[2] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006828 0x04, 0x05,
6829};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006830/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006831 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006832 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006833 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006834static const struct hda_input_mux alc260_test_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006835 {
6836 .num_items = 7,
6837 .items = {
6838 { "MIC1 pin", 0x0 },
6839 { "MIC2 pin", 0x1 },
6840 { "LINE1 pin", 0x2 },
6841 { "LINE2 pin", 0x3 },
6842 { "CD pin", 0x4 },
6843 { "LINE-OUT pin", 0x5 },
6844 { "HP-OUT pin", 0x6 },
6845 },
6846 },
6847 {
6848 .num_items = 8,
6849 .items = {
6850 { "MIC1 pin", 0x0 },
6851 { "MIC2 pin", 0x1 },
6852 { "LINE1 pin", 0x2 },
6853 { "LINE2 pin", 0x3 },
6854 { "CD pin", 0x4 },
6855 { "Mixer", 0x5 },
6856 { "LINE-OUT pin", 0x6 },
6857 { "HP-OUT pin", 0x7 },
6858 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006859 },
6860};
Takashi Iwaia9111322011-05-02 11:30:18 +02006861static const struct snd_kcontrol_new alc260_test_mixer[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006862 /* Output driver widgets */
6863 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6864 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6865 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6866 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6867 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6868 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6869
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006870 /* Modes for retasking pin widgets
6871 * Note: the ALC260 doesn't seem to act on requests to enable mic
6872 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6873 * mention this restriction. At this stage it's not clear whether
6874 * this behaviour is intentional or is a hardware bug in chip
6875 * revisions available at least up until early 2006. Therefore for
6876 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6877 * choices, but if it turns out that the lack of mic bias for these
6878 * NIDs is intentional we could change their modes from
6879 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6880 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006881 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6882 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6883 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6884 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6885 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6886 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6887
6888 /* Loopback mixer controls */
6889 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6890 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6891 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6892 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6893 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6894 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6895 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6896 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6897 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6898 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006899 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6900 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6901 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6902 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006903
6904 /* Controls for GPIO pins, assuming they are configured as outputs */
6905 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6906 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6907 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6908 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6909
Jonathan Woithe92621f12006-02-28 11:47:47 +01006910 /* Switches to allow the digital IO pins to be enabled. The datasheet
6911 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006912 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006913 */
6914 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6915 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6916
Jonathan Woithef8225f62008-01-08 12:16:54 +01006917 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6918 * this output to turn on an external amplifier.
6919 */
6920 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6921 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6922
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006923 { } /* end */
6924};
Takashi Iwaia9111322011-05-02 11:30:18 +02006925static const struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006926 /* Enable all GPIOs as outputs with an initial value of 0 */
6927 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6928 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6929 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6930
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006931 /* Enable retasking pins as output, initially without power amp */
6932 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6933 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6934 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6935 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6936 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6937 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6938
Jonathan Woithe92621f12006-02-28 11:47:47 +01006939 /* Disable digital (SPDIF) pins initially, but users can enable
6940 * them via a mixer switch. In the case of SPDIF-out, this initverb
6941 * payload also sets the generation to 0, output to be in "consumer"
6942 * PCM format, copyright asserted, no pre-emphasis and no validity
6943 * control.
6944 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006945 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6946 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6947
Kailang Yangea1fb292008-08-26 12:58:38 +02006948 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006949 * OUT1 sum bus when acting as an output.
6950 */
6951 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6952 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6953 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6954 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6955
6956 /* Start with output sum widgets muted and their output gains at min */
6957 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6958 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6959 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6960 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6961 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6962 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6963 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6964 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6965 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6966
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006967 /* Unmute retasking pin widget output buffers since the default
6968 * state appears to be output. As the pin mode is changed by the
6969 * user the pin mode control will take care of enabling the pin's
6970 * input/output buffers as needed.
6971 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006972 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6973 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6974 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6975 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6976 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6977 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6978 /* Also unmute the mono-out pin widget */
6979 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6980
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006981 /* Mute capture amp left and right */
6982 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006983 /* Set ADC connection select to match default mixer setting (mic1
6984 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006985 */
6986 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6987
6988 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006989 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006990 */
6991 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6992 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6993
6994 /* Mute all inputs to mixer widget (even unconnected ones) */
6995 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6996 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6997 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6998 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6999 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
7000 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
7001 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
7002 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
7003
7004 { }
7005};
7006#endif
7007
Kailang Yangdf694da2005-12-05 19:42:22 +01007008/*
7009 * for BIOS auto-configuration
7010 */
7011
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007012/* convert from pin to volume-mixer widget */
7013static hda_nid_t alc260_pin_to_vol_mix(hda_nid_t nid)
7014{
7015 if (nid >= 0x0f && nid <= 0x11)
7016 return nid - 0x7;
7017 else if (nid >= 0x12 && nid <= 0x15)
7018 return 0x08;
7019 else
7020 return 0;
7021}
7022
Kailang Yangdf694da2005-12-05 19:42:22 +01007023static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02007024 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01007025{
7026 hda_nid_t nid_vol;
7027 unsigned long vol_val, sw_val;
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007028 int chs, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01007029
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007030 nid_vol = alc260_pin_to_vol_mix(nid);
7031 if (!nid_vol)
Kailang Yangdf694da2005-12-05 19:42:22 +01007032 return 0; /* N/A */
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007033 if (nid == 0x11)
7034 chs = 2;
7035 else
7036 chs = 3;
7037 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, chs, 0, HDA_OUTPUT);
7038 sw_val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
Kailang Yangea1fb292008-08-26 12:58:38 +02007039
Takashi Iwai863b4512008-10-21 17:01:47 +02007040 if (!(*vol_bits & (1 << nid_vol))) {
7041 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007042 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02007043 if (err < 0)
7044 return err;
7045 *vol_bits |= (1 << nid_vol);
7046 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007047 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007048 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007049 return err;
7050 return 1;
7051}
7052
7053/* add playback controls from the parsed DAC table */
7054static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
7055 const struct auto_pin_cfg *cfg)
7056{
7057 hda_nid_t nid;
7058 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02007059 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007060
7061 spec->multiout.num_dacs = 1;
7062 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +02007063 spec->private_dac_nids[0] = 0x02;
Kailang Yangdf694da2005-12-05 19:42:22 +01007064
7065 nid = cfg->line_out_pins[0];
7066 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02007067 const char *pfx;
Takashi Iwai2e925dd2011-06-24 11:27:22 +02007068 int index;
7069 pfx = alc_get_line_out_pfx(spec, 0, true, &index);
Takashi Iwai23112d62009-08-25 16:07:08 +02007070 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007071 if (err < 0)
7072 return err;
7073 }
7074
Takashi Iwai82bc9552006-03-21 11:24:42 +01007075 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007076 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007077 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007078 if (err < 0)
7079 return err;
7080 }
7081
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007082 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007083 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007084 err = alc260_add_playback_controls(spec, nid, "Headphone",
7085 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007086 if (err < 0)
7087 return err;
7088 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007089 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007090}
7091
Kailang Yangdf694da2005-12-05 19:42:22 +01007092static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
7093 hda_nid_t nid, int pin_type,
7094 int sel_idx)
7095{
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007096 hda_nid_t mix;
7097
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007098 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007099 /* need the manual connection? */
7100 if (nid >= 0x12) {
7101 int idx = nid - 0x12;
7102 snd_hda_codec_write(codec, idx + 0x0b, 0,
7103 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01007104 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007105
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007106 mix = alc260_pin_to_vol_mix(nid);
7107 if (!mix)
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007108 return;
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007109 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007110 AMP_OUT_ZERO);
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007111 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7112 AMP_IN_UNMUTE(0));
7113 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7114 AMP_IN_UNMUTE(1));
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007115}
7116
Kailang Yangdf694da2005-12-05 19:42:22 +01007117static void alc260_auto_init_multi_out(struct hda_codec *codec)
7118{
7119 struct alc_spec *spec = codec->spec;
7120 hda_nid_t nid;
7121
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007122 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007123 if (nid) {
7124 int pin_type = get_pin_type(spec->autocfg.line_out_type);
7125 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
7126 }
Kailang Yangea1fb292008-08-26 12:58:38 +02007127
Takashi Iwai82bc9552006-03-21 11:24:42 +01007128 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007129 if (nid)
7130 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
7131
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007132 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007133 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007134 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007135}
Kailang Yangdf694da2005-12-05 19:42:22 +01007136
Kailang Yangdf694da2005-12-05 19:42:22 +01007137static int alc260_parse_auto_config(struct hda_codec *codec)
7138{
7139 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007140 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007141 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +01007142
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007143 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7144 alc260_ignore);
7145 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007146 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007147 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7148 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007149 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007150 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007151 return 0; /* can't find valid BIOS pin config */
Takashi Iwaib7821702011-07-06 15:12:46 +02007152 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007153 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007154 return err;
7155
7156 spec->multiout.max_channels = 2;
7157
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007158 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007159 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007160 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007161 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007162
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007163 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007164 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007165
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02007166 if (!spec->dual_adc_switch)
7167 alc_remove_invalid_adc_nids(codec);
7168
Kailang Yang6227cdc2010-02-25 08:36:52 +01007169 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007170
Kailang Yangdf694da2005-12-05 19:42:22 +01007171 return 1;
7172}
7173
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007174/* additional initialization for auto-configuration model */
7175static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007176{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007177 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007178 alc260_auto_init_multi_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +02007179 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +02007180 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007181 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007182 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007183 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007184}
7185
Takashi Iwaicb53c622007-08-10 17:21:45 +02007186#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02007187static const struct hda_amp_list alc260_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02007188 { 0x07, HDA_INPUT, 0 },
7189 { 0x07, HDA_INPUT, 1 },
7190 { 0x07, HDA_INPUT, 2 },
7191 { 0x07, HDA_INPUT, 3 },
7192 { 0x07, HDA_INPUT, 4 },
7193 { } /* end */
7194};
7195#endif
7196
Kailang Yangdf694da2005-12-05 19:42:22 +01007197/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007198 * Pin config fixes
7199 */
7200enum {
7201 PINFIX_HP_DC5750,
7202};
7203
Takashi Iwaifc091762010-08-04 23:53:36 +02007204static const struct alc_fixup alc260_fixups[] = {
7205 [PINFIX_HP_DC5750] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007206 .type = ALC_FIXUP_PINS,
7207 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +02007208 { 0x11, 0x90130110 }, /* speaker */
7209 { }
7210 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007211 },
7212};
7213
Takashi Iwaia9111322011-05-02 11:30:18 +02007214static const struct snd_pci_quirk alc260_fixup_tbl[] = {
Takashi Iwaifc091762010-08-04 23:53:36 +02007215 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7216 {}
7217};
7218
7219/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007220 * ALC260 configurations
7221 */
Takashi Iwaiea734962011-01-17 11:29:34 +01007222static const char * const alc260_models[ALC260_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007223 [ALC260_BASIC] = "basic",
7224 [ALC260_HP] = "hp",
7225 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007226 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007227 [ALC260_FUJITSU_S702X] = "fujitsu",
7228 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007229 [ALC260_WILL] = "will",
7230 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007231 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007232#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007233 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007234#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007235 [ALC260_AUTO] = "auto",
7236};
7237
Takashi Iwaia9111322011-05-02 11:30:18 +02007238static const struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007239 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007240 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007241 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007242 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007243 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007244 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007245 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007246 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007247 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007248 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7249 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7250 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7251 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7252 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7253 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7254 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7255 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7256 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007257 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007258 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007259 {}
7260};
7261
Takashi Iwaia9111322011-05-02 11:30:18 +02007262static const struct alc_config_preset alc260_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007263 [ALC260_BASIC] = {
7264 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007265 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007266 .init_verbs = { alc260_init_verbs },
7267 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7268 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007269 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007270 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007271 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7272 .channel_mode = alc260_modes,
7273 .input_mux = &alc260_capture_source,
7274 },
7275 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007276 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007277 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007278 .init_verbs = { alc260_init_verbs,
7279 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007280 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7281 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007282 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7283 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007284 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7285 .channel_mode = alc260_modes,
7286 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007287 .unsol_event = alc_sku_unsol_event,
7288 .setup = alc260_hp_setup,
7289 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007290 },
Kailang Yang3f878302008-08-26 13:02:23 +02007291 [ALC260_HP_DC7600] = {
7292 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007293 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007294 .init_verbs = { alc260_init_verbs,
7295 alc260_hp_dc7600_verbs },
7296 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7297 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007298 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7299 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007300 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7301 .channel_mode = alc260_modes,
7302 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007303 .unsol_event = alc_sku_unsol_event,
7304 .setup = alc260_hp_3012_setup,
7305 .init_hook = alc_inithook,
Kailang Yang3f878302008-08-26 13:02:23 +02007306 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007307 [ALC260_HP_3013] = {
7308 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007309 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007310 .init_verbs = { alc260_hp_3013_init_verbs,
7311 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007312 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7313 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007314 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7315 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007316 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7317 .channel_mode = alc260_modes,
7318 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007319 .unsol_event = alc_sku_unsol_event,
7320 .setup = alc260_hp_3013_setup,
7321 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007322 },
7323 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007324 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007325 .init_verbs = { alc260_fujitsu_init_verbs },
7326 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7327 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007328 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7329 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007330 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7331 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007332 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7333 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007334 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007335 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007336 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007337 .init_verbs = { alc260_acer_init_verbs },
7338 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7339 .dac_nids = alc260_dac_nids,
7340 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7341 .adc_nids = alc260_dual_adc_nids,
7342 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7343 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007344 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7345 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007346 },
Michael Schwingencc959482009-02-22 18:58:45 +01007347 [ALC260_FAVORIT100] = {
7348 .mixers = { alc260_favorit100_mixer },
7349 .init_verbs = { alc260_favorit100_init_verbs },
7350 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7351 .dac_nids = alc260_dac_nids,
7352 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7353 .adc_nids = alc260_dual_adc_nids,
7354 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7355 .channel_mode = alc260_modes,
7356 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7357 .input_mux = alc260_favorit100_capture_sources,
7358 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007359 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007360 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007361 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7362 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7363 .dac_nids = alc260_dac_nids,
7364 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7365 .adc_nids = alc260_adc_nids,
7366 .dig_out_nid = ALC260_DIGOUT_NID,
7367 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7368 .channel_mode = alc260_modes,
7369 .input_mux = &alc260_capture_source,
7370 },
7371 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007372 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007373 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7374 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7375 .dac_nids = alc260_dac_nids,
7376 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7377 .adc_nids = alc260_adc_nids,
7378 .dig_out_nid = ALC260_DIGOUT_NID,
7379 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7380 .channel_mode = alc260_modes,
7381 .input_mux = &alc260_capture_source,
7382 .unsol_event = alc260_replacer_672v_unsol_event,
7383 .init_hook = alc260_replacer_672v_automute,
7384 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007385#ifdef CONFIG_SND_DEBUG
7386 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007387 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007388 .init_verbs = { alc260_test_init_verbs },
7389 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7390 .dac_nids = alc260_test_dac_nids,
7391 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7392 .adc_nids = alc260_test_adc_nids,
7393 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7394 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007395 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7396 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007397 },
7398#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007399};
7400
Linus Torvalds1da177e2005-04-16 15:20:36 -07007401static int patch_alc260(struct hda_codec *codec)
7402{
7403 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007404 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007406 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007407 if (spec == NULL)
7408 return -ENOMEM;
7409
7410 codec->spec = spec;
7411
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007412 spec->mixer_nid = 0x07;
7413
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007414 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7415 alc260_models,
7416 alc260_cfg_tbl);
7417 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007418 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007419 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007420 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007421 }
7422
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007423 if (board_config == ALC260_AUTO) {
7424 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
7425 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7426 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007427
Kailang Yangdf694da2005-12-05 19:42:22 +01007428 if (board_config == ALC260_AUTO) {
7429 /* automatic parse from the BIOS config */
7430 err = alc260_parse_auto_config(codec);
7431 if (err < 0) {
7432 alc_free(codec);
7433 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007434 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007435 printk(KERN_INFO
7436 "hda_codec: Cannot set up configuration "
7437 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007438 board_config = ALC260_BASIC;
7439 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007441
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007442 err = snd_hda_attach_beep_device(codec, 0x1);
7443 if (err < 0) {
7444 alc_free(codec);
7445 return err;
7446 }
7447
Kailang Yangdf694da2005-12-05 19:42:22 +01007448 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007449 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007450
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007451 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02007452 alc_auto_fill_adc_caps(codec);
7453 alc_remove_invalid_adc_nids(codec);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007454 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007455 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007456 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007457
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007458 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaifc091762010-08-04 23:53:36 +02007459
Takashi Iwai2134ea42008-01-10 16:53:55 +01007460 spec->vmaster_nid = 0x08;
7461
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007463 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007464 spec->init_hook = alc260_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +02007465 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007466#ifdef CONFIG_SND_HDA_POWER_SAVE
7467 if (!spec->loopback.amplist)
7468 spec->loopback.amplist = alc260_loopbacks;
7469#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007470
7471 return 0;
7472}
7473
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007474
Linus Torvalds1da177e2005-04-16 15:20:36 -07007475/*
Takashi Iwai49535502009-06-30 15:28:30 +02007476 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007477 *
7478 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7479 * configuration. Each pin widget can choose any input DACs and a mixer.
7480 * Each ADC is connected from a mixer of all inputs. This makes possible
7481 * 6-channel independent captures.
7482 *
7483 * In addition, an independent DAC for the multi-playback (not used in this
7484 * driver yet).
7485 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007486#define ALC882_DIGOUT_NID 0x06
7487#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007488#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7489#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7490#define ALC1200_DIGOUT_NID 0x10
7491
Linus Torvalds1da177e2005-04-16 15:20:36 -07007492
Takashi Iwaia9111322011-05-02 11:30:18 +02007493static const struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007494 { 8, NULL }
7495};
7496
Takashi Iwai49535502009-06-30 15:28:30 +02007497/* DACs */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007498static const hda_nid_t alc882_dac_nids[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007499 /* front, rear, clfe, rear_surr */
7500 0x02, 0x03, 0x04, 0x05
7501};
Takashi Iwai49535502009-06-30 15:28:30 +02007502#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007503
Takashi Iwai49535502009-06-30 15:28:30 +02007504/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007505#define alc882_adc_nids alc880_adc_nids
7506#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007507#define alc883_adc_nids alc882_adc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007508static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7509static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
Takashi Iwai49535502009-06-30 15:28:30 +02007510#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007512static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7513static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007514#define alc883_capsrc_nids alc882_capsrc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007515static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
Takashi Iwai49535502009-06-30 15:28:30 +02007516#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007517
Linus Torvalds1da177e2005-04-16 15:20:36 -07007518/* input MUX */
7519/* FIXME: should be a matrix-type input source selection */
7520
Takashi Iwaia9111322011-05-02 11:30:18 +02007521static const struct hda_input_mux alc882_capture_source = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007522 .num_items = 4,
7523 .items = {
7524 { "Mic", 0x0 },
7525 { "Front Mic", 0x1 },
7526 { "Line", 0x2 },
7527 { "CD", 0x4 },
7528 },
7529};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007530
Takashi Iwai49535502009-06-30 15:28:30 +02007531#define alc883_capture_source alc882_capture_source
7532
Takashi Iwaia9111322011-05-02 11:30:18 +02007533static const struct hda_input_mux alc889_capture_source = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007534 .num_items = 3,
7535 .items = {
7536 { "Front Mic", 0x0 },
7537 { "Mic", 0x3 },
7538 { "Line", 0x2 },
7539 },
7540};
7541
Takashi Iwaia9111322011-05-02 11:30:18 +02007542static const struct hda_input_mux mb5_capture_source = {
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007543 .num_items = 3,
7544 .items = {
7545 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307546 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007547 { "CD", 0x4 },
7548 },
7549};
7550
Takashi Iwaia9111322011-05-02 11:30:18 +02007551static const struct hda_input_mux macmini3_capture_source = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007552 .num_items = 2,
7553 .items = {
7554 { "Line", 0x2 },
7555 { "CD", 0x4 },
7556 },
7557};
7558
Takashi Iwaia9111322011-05-02 11:30:18 +02007559static const struct hda_input_mux alc883_3stack_6ch_intel = {
Takashi Iwai49535502009-06-30 15:28:30 +02007560 .num_items = 4,
7561 .items = {
7562 { "Mic", 0x1 },
7563 { "Front Mic", 0x0 },
7564 { "Line", 0x2 },
7565 { "CD", 0x4 },
7566 },
7567};
7568
Takashi Iwaia9111322011-05-02 11:30:18 +02007569static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007570 .num_items = 2,
7571 .items = {
7572 { "Mic", 0x1 },
7573 { "Line", 0x2 },
7574 },
7575};
7576
Takashi Iwaia9111322011-05-02 11:30:18 +02007577static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007578 .num_items = 4,
7579 .items = {
7580 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007581 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007582 { "Line", 0x2 },
7583 { "CD", 0x4 },
7584 },
7585};
7586
Takashi Iwaia9111322011-05-02 11:30:18 +02007587static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007588 .num_items = 2,
7589 .items = {
7590 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007591 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007592 },
7593};
7594
Takashi Iwaia9111322011-05-02 11:30:18 +02007595static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007596 .num_items = 3,
7597 .items = {
7598 { "Mic", 0x0 },
7599 { "Front Mic", 0x1 },
7600 { "Line", 0x4 },
7601 },
7602};
7603
Takashi Iwaia9111322011-05-02 11:30:18 +02007604static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007605 .num_items = 2,
7606 .items = {
7607 { "Mic", 0x0 },
7608 { "Line", 0x2 },
7609 },
7610};
7611
Takashi Iwaia9111322011-05-02 11:30:18 +02007612static const struct hda_input_mux alc889A_mb31_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007613 .num_items = 2,
7614 .items = {
7615 { "Mic", 0x0 },
7616 /* Front Mic (0x01) unused */
7617 { "Line", 0x2 },
7618 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007619 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007620 },
7621};
7622
Takashi Iwaia9111322011-05-02 11:30:18 +02007623static const struct hda_input_mux alc889A_imac91_capture_source = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007624 .num_items = 2,
7625 .items = {
7626 { "Mic", 0x01 },
7627 { "Line", 0x2 }, /* Not sure! */
7628 },
7629};
7630
Takashi Iwai49535502009-06-30 15:28:30 +02007631/*
7632 * 2ch mode
7633 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007634static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007635 { 2, NULL }
7636};
7637
Kailang Yangdf694da2005-12-05 19:42:22 +01007638/*
Kailang Yang272a5272007-05-14 11:00:38 +02007639 * 2ch mode
7640 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007641static const struct hda_verb alc882_3ST_ch2_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007642 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7643 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7644 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7645 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7646 { } /* end */
7647};
7648
7649/*
Takashi Iwai49535502009-06-30 15:28:30 +02007650 * 4ch mode
7651 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007652static const struct hda_verb alc882_3ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007653 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7654 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7655 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7656 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7657 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7658 { } /* end */
7659};
7660
7661/*
Kailang Yang272a5272007-05-14 11:00:38 +02007662 * 6ch mode
7663 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007664static const struct hda_verb alc882_3ST_ch6_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007665 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7666 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7667 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7668 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7669 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7670 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7671 { } /* end */
7672};
7673
Takashi Iwaia9111322011-05-02 11:30:18 +02007674static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007675 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007676 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007677 { 6, alc882_3ST_ch6_init },
7678};
7679
Takashi Iwai49535502009-06-30 15:28:30 +02007680#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7681
Kailang Yang272a5272007-05-14 11:00:38 +02007682/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307683 * 2ch mode
7684 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007685static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307686 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7687 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7688 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7689 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7690 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7691 { } /* end */
7692};
7693
7694/*
7695 * 4ch mode
7696 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007697static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307698 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7699 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7700 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7701 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7702 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7703 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7704 { } /* end */
7705};
7706
7707/*
7708 * 6ch mode
7709 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007710static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307711 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7712 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7713 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7714 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7715 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7716 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7717 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7718 { } /* end */
7719};
7720
Takashi Iwaia9111322011-05-02 11:30:18 +02007721static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307722 { 2, alc883_3ST_ch2_clevo_init },
7723 { 4, alc883_3ST_ch4_clevo_init },
7724 { 6, alc883_3ST_ch6_clevo_init },
7725};
7726
7727
7728/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007729 * 6ch mode
7730 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007731static const struct hda_verb alc882_sixstack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007732 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7733 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7734 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7735 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7736 { } /* end */
7737};
7738
7739/*
7740 * 8ch mode
7741 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007742static const struct hda_verb alc882_sixstack_ch8_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007743 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7744 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7745 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7746 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7747 { } /* end */
7748};
7749
Takashi Iwaia9111322011-05-02 11:30:18 +02007750static const struct hda_channel_mode alc882_sixstack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007751 { 6, alc882_sixstack_ch6_init },
7752 { 8, alc882_sixstack_ch8_init },
7753};
7754
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007755
7756/* Macbook Air 2,1 */
7757
Takashi Iwaia9111322011-05-02 11:30:18 +02007758static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007759 { 2, NULL },
7760};
7761
Takashi Iwai87350ad2007-08-16 18:19:38 +02007762/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007763 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007764 */
7765
7766/*
7767 * 2ch mode
7768 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007769static const struct hda_verb alc885_mbp_ch2_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007770 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7771 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7772 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7773 { } /* end */
7774};
7775
7776/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007777 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007778 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007779static const struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007780 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7781 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7782 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7783 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7784 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7785 { } /* end */
7786};
7787
Takashi Iwaia9111322011-05-02 11:30:18 +02007788static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007789 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007790 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007791};
7792
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007793/*
7794 * 2ch
7795 * Speakers/Woofer/HP = Front
7796 * LineIn = Input
7797 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007798static const struct hda_verb alc885_mb5_ch2_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007799 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7800 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7801 { } /* end */
7802};
7803
7804/*
7805 * 6ch mode
7806 * Speakers/HP = Front
7807 * Woofer = LFE
7808 * LineIn = Surround
7809 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007810static const struct hda_verb alc885_mb5_ch6_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007811 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7812 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7813 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7814 { } /* end */
7815};
7816
Takashi Iwaia9111322011-05-02 11:30:18 +02007817static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007818 { 2, alc885_mb5_ch2_init },
7819 { 6, alc885_mb5_ch6_init },
7820};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007821
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007822#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02007823
7824/*
7825 * 2ch mode
7826 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007827static const struct hda_verb alc883_4ST_ch2_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007828 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7829 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7830 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7831 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7832 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7833 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7834 { } /* end */
7835};
7836
7837/*
7838 * 4ch mode
7839 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007840static const struct hda_verb alc883_4ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007841 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7842 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7843 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7844 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7845 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7846 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7847 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7848 { } /* end */
7849};
7850
7851/*
7852 * 6ch mode
7853 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007854static const struct hda_verb alc883_4ST_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007855 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7856 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7857 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7858 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7859 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7860 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7861 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7862 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7863 { } /* end */
7864};
7865
7866/*
7867 * 8ch mode
7868 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007869static const struct hda_verb alc883_4ST_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007870 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7871 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7872 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7873 { 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 alc883_4ST_8ch_modes[4] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007883 { 2, alc883_4ST_ch2_init },
7884 { 4, alc883_4ST_ch4_init },
7885 { 6, alc883_4ST_ch6_init },
7886 { 8, alc883_4ST_ch8_init },
7887};
7888
7889
7890/*
7891 * 2ch mode
7892 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007893static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007894 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7895 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7896 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7897 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7898 { } /* end */
7899};
7900
7901/*
7902 * 4ch mode
7903 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007904static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007905 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7906 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7907 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7908 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7909 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7910 { } /* end */
7911};
7912
7913/*
7914 * 6ch mode
7915 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007916static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007917 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7918 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7919 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7920 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7921 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7922 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7923 { } /* end */
7924};
7925
Takashi Iwaia9111322011-05-02 11:30:18 +02007926static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007927 { 2, alc883_3ST_ch2_intel_init },
7928 { 4, alc883_3ST_ch4_intel_init },
7929 { 6, alc883_3ST_ch6_intel_init },
7930};
7931
7932/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007933 * 2ch mode
7934 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007935static const struct hda_verb alc889_ch2_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007936 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7937 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7938 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7939 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7940 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7941 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7942 { } /* end */
7943};
7944
7945/*
Takashi Iwai49535502009-06-30 15:28:30 +02007946 * 6ch mode
7947 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007948static const struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007949 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7950 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7951 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7952 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7953 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007954 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7955 { } /* end */
7956};
7957
7958/*
7959 * 8ch mode
7960 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007961static const struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007962 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7963 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7964 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7965 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7966 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007967 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7968 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007969 { } /* end */
7970};
7971
Takashi Iwaia9111322011-05-02 11:30:18 +02007972static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007973 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007974 { 6, alc889_ch6_intel_init },
7975 { 8, alc889_ch8_intel_init },
7976};
7977
7978/*
7979 * 6ch mode
7980 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007981static const struct hda_verb alc883_sixstack_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007982 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7983 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7984 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7985 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7986 { } /* end */
7987};
7988
7989/*
7990 * 8ch mode
7991 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007992static const struct hda_verb alc883_sixstack_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007993 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7994 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7995 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7996 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7997 { } /* end */
7998};
7999
Takashi Iwaia9111322011-05-02 11:30:18 +02008000static const struct hda_channel_mode alc883_sixstack_modes[2] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008001 { 6, alc883_sixstack_ch6_init },
8002 { 8, alc883_sixstack_ch8_init },
8003};
8004
8005
Linus Torvalds1da177e2005-04-16 15:20:36 -07008006/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
8007 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
8008 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008009static const struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02008010 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008011 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008012 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008013 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008014 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8015 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008016 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8017 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008018 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008019 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008020 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8021 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8022 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8023 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8024 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8025 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008026 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008027 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8028 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008029 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008030 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008031 { } /* end */
8032};
8033
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008034/* Macbook Air 2,1 same control for HP and internal Speaker */
8035
Takashi Iwaia9111322011-05-02 11:30:18 +02008036static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008037 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8038 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
8039 { }
8040};
8041
8042
Takashi Iwaia9111322011-05-02 11:30:18 +02008043static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008044 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8045 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
8046 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8047 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
8048 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01008049 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8050 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008051 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8052 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008053 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
8054 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008055 { } /* end */
8056};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008057
Takashi Iwaia9111322011-05-02 11:30:18 +02008058static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008059 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8060 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8061 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8062 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8063 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8064 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10308065 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8066 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09308067 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8068 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008069 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8070 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008071 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
8072 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008073 { } /* end */
8074};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008075
Takashi Iwaia9111322011-05-02 11:30:18 +02008076static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008077 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8078 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8079 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8080 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8081 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8082 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
8083 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8084 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
8085 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8086 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008087 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008088 { } /* end */
8089};
8090
Takashi Iwaia9111322011-05-02 11:30:18 +02008091static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008092 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8093 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008094 { } /* end */
8095};
8096
8097
Takashi Iwaia9111322011-05-02 11:30:18 +02008098static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02008099 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8100 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8101 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8102 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8103 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8104 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8105 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008106 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008107 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008108 { } /* end */
8109};
8110
Takashi Iwaia9111322011-05-02 11:30:18 +02008111static const struct snd_kcontrol_new alc882_targa_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008112 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8113 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8114 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8115 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8116 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8117 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8118 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8119 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8120 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008121 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008122 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8123 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008124 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008125 { } /* end */
8126};
8127
8128/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8129 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8130 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008131static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008132 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8133 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8134 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8135 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8136 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8137 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8138 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8139 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8140 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8141 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8142 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8143 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008144 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008145 { } /* end */
8146};
8147
Takashi Iwaia9111322011-05-02 11:30:18 +02008148static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008149 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8150 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8151 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8152 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8153 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8154 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8155 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8156 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008157 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008158 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008159 { } /* end */
8160};
8161
Takashi Iwaia9111322011-05-02 11:30:18 +02008162static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008163 {
8164 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8165 .name = "Channel Mode",
8166 .info = alc_ch_mode_info,
8167 .get = alc_ch_mode_get,
8168 .put = alc_ch_mode_put,
8169 },
8170 { } /* end */
8171};
8172
Takashi Iwaia9111322011-05-02 11:30:18 +02008173static const struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008174 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008175 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8176 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008177 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008178 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8179 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008180 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008181 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8182 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008183 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008184 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8185 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008186
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008187 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008188 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008189 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008190 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008191 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008192 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008193 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008194 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008195 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008196 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008197 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008198 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008199 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008200 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008201 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008202 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008203 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008204 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008205 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8206 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008207 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008208 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8209 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008210 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008211 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8212 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8213 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8214 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8215 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008216 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008217 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008218
8219 /* FIXME: use matrix-type input source selection */
8220 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008221 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008222 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008223 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008224 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008225 /* ADC2: mute amp left and right */
8226 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008227 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008228 /* ADC3: mute amp left and right */
8229 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008230 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008231
8232 { }
8233};
8234
Takashi Iwaia9111322011-05-02 11:30:18 +02008235static const struct hda_verb alc882_adc1_init_verbs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008236 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8237 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8238 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8239 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8240 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8241 /* ADC1: mute amp left and right */
8242 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8243 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8244 { }
8245};
8246
Takashi Iwaia9111322011-05-02 11:30:18 +02008247static const struct hda_verb alc882_eapd_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008248 /* change to EAPD mode */
8249 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008250 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008251 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008252};
8253
Takashi Iwaia9111322011-05-02 11:30:18 +02008254static const struct hda_verb alc889_eapd_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008255 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8256 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8257 { }
8258};
8259
Takashi Iwaia9111322011-05-02 11:30:18 +02008260static const struct hda_verb alc_hp15_unsol_verbs[] = {
Wu Fengguang6732bd02009-07-30 09:19:14 +02008261 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8262 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8263 {}
8264};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008265
Takashi Iwaia9111322011-05-02 11:30:18 +02008266static const struct hda_verb alc885_init_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008267 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008268 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8269 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008270 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008271 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8272 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008273 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008274 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8275 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008276 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008277 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8278 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008279
8280 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008281 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008282 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8283 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8284 /* Front Pin: output 0 (0x0c) */
8285 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8286 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8287 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8288 /* Rear Pin: output 1 (0x0d) */
8289 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8290 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8291 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8292 /* CLFE Pin: output 2 (0x0e) */
8293 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8294 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8295 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8296 /* Side Pin: output 3 (0x0f) */
8297 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8298 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8299 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8300 /* Mic (rear) pin: input vref at 80% */
8301 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8302 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8303 /* Front Mic pin: input vref at 80% */
8304 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8305 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8306 /* Line In pin: input */
8307 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8308 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8309
8310 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8311 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008312 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008313 /* Input mixer2 */
8314 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008315 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008316 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008317 /* ADC2: mute amp left and right */
8318 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8319 /* ADC3: mute amp left and right */
8320 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8321
8322 { }
8323};
8324
Takashi Iwaia9111322011-05-02 11:30:18 +02008325static const struct hda_verb alc885_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008326 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8327 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8328 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8329 { }
8330};
8331
8332
8333/* Unmute Selector 24h and set the default input to front mic */
Takashi Iwaia9111322011-05-02 11:30:18 +02008334static const struct hda_verb alc889_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008335 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8336 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8337 { }
8338};
8339
8340
Takashi Iwai49535502009-06-30 15:28:30 +02008341#define alc883_init_verbs alc882_base_init_verbs
8342
Tobin Davis9102cd12006-12-15 10:02:12 +01008343/* Mac Pro test */
Takashi Iwaia9111322011-05-02 11:30:18 +02008344static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008345 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8346 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8347 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8348 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8349 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008350 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008351 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8352 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008353 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008354 { } /* end */
8355};
8356
Takashi Iwaia9111322011-05-02 11:30:18 +02008357static const struct hda_verb alc882_macpro_init_verbs[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008358 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8359 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8360 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8361 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8362 /* Front Pin: output 0 (0x0c) */
8363 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8364 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8365 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8366 /* Front Mic pin: input vref at 80% */
8367 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8368 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8369 /* Speaker: output */
8370 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8371 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8372 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8373 /* Headphone output (output 0 - 0x0c) */
8374 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8375 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8376 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8377
8378 /* FIXME: use matrix-type input source selection */
8379 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8380 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8381 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8382 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8383 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8384 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8385 /* Input mixer2 */
8386 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8387 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8388 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8389 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8390 /* Input mixer3 */
8391 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8392 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8393 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8394 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8395 /* ADC1: mute amp left and right */
8396 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8397 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8398 /* ADC2: mute amp left and right */
8399 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8400 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8401 /* ADC3: mute amp left and right */
8402 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8403 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8404
8405 { }
8406};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008407
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008408/* Macbook 5,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008409static const struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008410 /* DACs */
8411 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8412 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8413 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8414 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008415 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8417 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8418 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008419 /* Surround mixer */
8420 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8421 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8422 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8423 /* LFE mixer */
8424 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8425 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8427 /* HP mixer */
8428 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8429 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8430 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8431 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008432 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8433 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008434 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8435 /* LFE Pin (0x0e) */
8436 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8437 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8438 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8439 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008440 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8441 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008442 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308443 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008444 /* Front Mic pin: input vref at 80% */
8445 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8446 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8447 /* Line In pin */
8448 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8449 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8450
Alex Murrayb8f171e2010-06-14 12:08:43 +09308451 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8452 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8453 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008454 { }
8455};
8456
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008457/* Macmini 3,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008458static const struct hda_verb alc885_macmini3_init_verbs[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008459 /* DACs */
8460 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8461 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8462 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8463 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8464 /* Front mixer */
8465 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8466 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8467 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8468 /* Surround mixer */
8469 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8470 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8471 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8472 /* LFE mixer */
8473 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8474 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8475 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8476 /* HP mixer */
8477 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8478 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8479 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8480 /* Front Pin (0x0c) */
8481 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8482 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8483 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8484 /* LFE Pin (0x0e) */
8485 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8486 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8487 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8488 /* HP Pin (0x0f) */
8489 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8490 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8491 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8492 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8493 /* Line In pin */
8494 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8495 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8496
8497 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8498 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8499 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8500 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8501 { }
8502};
8503
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008504
Takashi Iwaia9111322011-05-02 11:30:18 +02008505static const struct hda_verb alc885_mba21_init_verbs[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008506 /*Internal and HP Speaker Mixer*/
8507 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8510 /*Internal Speaker Pin (0x0c)*/
8511 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8512 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8513 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8514 /* HP Pin: output 0 (0x0e) */
8515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8516 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8517 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8518 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8519 /* Line in (is hp when jack connected)*/
8520 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8521 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8522
8523 { }
8524 };
8525
8526
Takashi Iwai87350ad2007-08-16 18:19:38 +02008527/* Macbook Pro rev3 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008528static const struct hda_verb alc885_mbp3_init_verbs[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02008529 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8530 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8531 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8532 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8533 /* Rear mixer */
8534 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8535 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8536 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008537 /* HP mixer */
8538 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8539 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8540 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008541 /* Front Pin: output 0 (0x0c) */
8542 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8543 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8544 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008545 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008546 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008547 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8548 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008549 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8550 /* Mic (rear) pin: input vref at 80% */
8551 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8552 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8553 /* Front Mic pin: input vref at 80% */
8554 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8555 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8556 /* Line In pin: use output 1 when in LineOut mode */
8557 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8558 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8559 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8560
8561 /* FIXME: use matrix-type input source selection */
8562 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8563 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8564 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8565 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8566 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8567 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8568 /* Input mixer2 */
8569 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8570 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8571 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8572 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8573 /* Input mixer3 */
8574 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8575 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8576 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8577 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8578 /* ADC1: mute amp left and right */
8579 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8580 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8581 /* ADC2: mute amp left and right */
8582 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8583 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8584 /* ADC3: mute amp left and right */
8585 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8586 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8587
8588 { }
8589};
8590
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008591/* iMac 9,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008592static const struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008593 /* Internal Speaker Pin (0x0c) */
8594 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8595 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8596 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8597 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8598 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8599 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8600 /* HP Pin: Rear */
8601 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8602 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8603 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8604 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8605 /* Line in Rear */
8606 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8607 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8608 /* Front Mic pin: input vref at 80% */
8609 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8610 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008611 /* Rear mixer */
8612 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8613 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8614 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008615 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8616 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8617 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8618 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8619 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008620 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8621 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8622 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8623 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008624 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008625 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8626 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8627 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8628 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008629 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008630 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8631 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8632 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8633 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008634 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008635 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8636 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008637 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008638 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8639 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008640 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008641 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8642 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008643 { }
8644};
8645
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008646/* iMac 24 mixer. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008647static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008648 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8649 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8650 { } /* end */
8651};
8652
8653/* iMac 24 init verbs. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008654static const struct hda_verb alc885_imac24_init_verbs[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008655 /* Internal speakers: output 0 (0x0c) */
8656 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8657 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8658 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8659 /* Internal speakers: output 0 (0x0c) */
8660 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8661 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8662 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8663 /* Headphone: output 0 (0x0c) */
8664 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8665 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8666 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8667 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8668 /* Front Mic: input vref at 80% */
8669 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8670 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8671 { }
8672};
8673
8674/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008675static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008676{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008677 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008678
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008679 spec->autocfg.hp_pins[0] = 0x14;
8680 spec->autocfg.speaker_pins[0] = 0x18;
8681 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008682 spec->automute = 1;
8683 spec->automute_mode = ALC_AUTOMUTE_AMP;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008684}
8685
Takashi Iwai9d54f082010-02-22 08:34:40 +01008686#define alc885_mb5_setup alc885_imac24_setup
8687#define alc885_macmini3_setup alc885_imac24_setup
8688
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008689/* Macbook Air 2,1 */
8690static void alc885_mba21_setup(struct hda_codec *codec)
8691{
8692 struct alc_spec *spec = codec->spec;
8693
8694 spec->autocfg.hp_pins[0] = 0x14;
8695 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02008696 spec->automute = 1;
8697 spec->automute_mode = ALC_AUTOMUTE_AMP;
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008698}
8699
8700
8701
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008702static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008703{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008704 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008705
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008706 spec->autocfg.hp_pins[0] = 0x15;
8707 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02008708 spec->automute = 1;
8709 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008710}
8711
Takashi Iwai9d54f082010-02-22 08:34:40 +01008712static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308713{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008714 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308715
Takashi Iwai9d54f082010-02-22 08:34:40 +01008716 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008717 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008718 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008719 spec->automute = 1;
8720 spec->automute_mode = ALC_AUTOMUTE_AMP;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008721}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008722
Takashi Iwaia9111322011-05-02 11:30:18 +02008723static const struct hda_verb alc882_targa_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008724 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8725 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8726
8727 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8728 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008729
Kailang Yang272a5272007-05-14 11:00:38 +02008730 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8731 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8732 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8733
8734 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008735 { } /* end */
8736};
8737
8738/* toggle speaker-output according to the hp-jack state */
8739static void alc882_targa_automute(struct hda_codec *codec)
8740{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008741 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02008742 alc_hp_automute(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008743 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008744 spec->jack_present ? 1 : 3);
8745}
8746
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008747static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008748{
8749 struct alc_spec *spec = codec->spec;
8750
8751 spec->autocfg.hp_pins[0] = 0x14;
8752 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02008753 spec->automute = 1;
8754 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02008755}
8756
8757static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8758{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008759 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008760 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008761}
8762
Takashi Iwaia9111322011-05-02 11:30:18 +02008763static const struct hda_verb alc882_asus_a7j_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008764 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8765 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8766
8767 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8768 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8769 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008770
Kailang Yang272a5272007-05-14 11:00:38 +02008771 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8772 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8773 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8774
8775 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8776 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8777 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8778 { } /* end */
8779};
8780
Takashi Iwaia9111322011-05-02 11:30:18 +02008781static const struct hda_verb alc882_asus_a7m_verbs[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008782 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8783 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8784
8785 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8786 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8787 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008788
Takashi Iwai914759b2007-09-06 14:52:04 +02008789 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8790 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8791 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8792
8793 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8794 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8795 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8796 { } /* end */
8797};
8798
Tobin Davis9102cd12006-12-15 10:02:12 +01008799static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8800{
8801 unsigned int gpiostate, gpiomask, gpiodir;
8802
8803 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8804 AC_VERB_GET_GPIO_DATA, 0);
8805
8806 if (!muted)
8807 gpiostate |= (1 << pin);
8808 else
8809 gpiostate &= ~(1 << pin);
8810
8811 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8812 AC_VERB_GET_GPIO_MASK, 0);
8813 gpiomask |= (1 << pin);
8814
8815 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8816 AC_VERB_GET_GPIO_DIRECTION, 0);
8817 gpiodir |= (1 << pin);
8818
8819
8820 snd_hda_codec_write(codec, codec->afg, 0,
8821 AC_VERB_SET_GPIO_MASK, gpiomask);
8822 snd_hda_codec_write(codec, codec->afg, 0,
8823 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8824
8825 msleep(1);
8826
8827 snd_hda_codec_write(codec, codec->afg, 0,
8828 AC_VERB_SET_GPIO_DATA, gpiostate);
8829}
8830
Takashi Iwai7debbe52007-08-16 15:01:03 +02008831/* set up GPIO at initialization */
8832static void alc885_macpro_init_hook(struct hda_codec *codec)
8833{
8834 alc882_gpio_mute(codec, 0, 0);
8835 alc882_gpio_mute(codec, 1, 0);
8836}
8837
8838/* set up GPIO and update auto-muting at initialization */
8839static void alc885_imac24_init_hook(struct hda_codec *codec)
8840{
8841 alc885_macpro_init_hook(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02008842 alc_hp_automute(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008843}
8844
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008845/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008846static const struct hda_verb alc889A_mb31_ch2_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008847 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8848 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8849 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8850 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8851 { } /* end */
8852};
8853
8854/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008855static const struct hda_verb alc889A_mb31_ch4_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008856 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8857 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8858 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8859 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8860 { } /* end */
8861};
8862
8863/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008864static const struct hda_verb alc889A_mb31_ch5_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008865 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8866 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8867 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8868 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8869 { } /* end */
8870};
8871
8872/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008873static const struct hda_verb alc889A_mb31_ch6_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008874 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8875 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8876 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8877 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8878 { } /* end */
8879};
8880
Takashi Iwaia9111322011-05-02 11:30:18 +02008881static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008882 { 2, alc889A_mb31_ch2_init },
8883 { 4, alc889A_mb31_ch4_init },
8884 { 5, alc889A_mb31_ch5_init },
8885 { 6, alc889A_mb31_ch6_init },
8886};
8887
Takashi Iwaia9111322011-05-02 11:30:18 +02008888static const struct hda_verb alc883_medion_eapd_verbs[] = {
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008889 /* eanable EAPD on medion laptop */
8890 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8891 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8892 { }
8893};
8894
Takashi Iwai49535502009-06-30 15:28:30 +02008895#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008896
Takashi Iwaia9111322011-05-02 11:30:18 +02008897static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008898 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8899 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8900 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8901 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8902 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8903 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8904 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8905 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008906 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008907 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8908 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008909 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008910 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008911 { } /* end */
8912};
8913
Takashi Iwaia9111322011-05-02 11:30:18 +02008914static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008915 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8916 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8917 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8918 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8919 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008920 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008921 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008922 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008923 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008924 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008925 { } /* end */
8926};
8927
Takashi Iwaia9111322011-05-02 11:30:18 +02008928static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01008929 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8930 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8931 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8932 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8933 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008934 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008935 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008936 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008937 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008938 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008939 { } /* end */
8940};
8941
Takashi Iwaia9111322011-05-02 11:30:18 +02008942static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008943 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8944 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8945 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8946 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8947 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8948 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8949 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8950 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008951 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008952 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8953 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008954 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008955 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008956 { } /* end */
8957};
8958
Takashi Iwaia9111322011-05-02 11:30:18 +02008959static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008960 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8961 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8962 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8963 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8964 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8965 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8966 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8967 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8968 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8969 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8970 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8971 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8972 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8973 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008974 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008975 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8976 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008977 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008978 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008979 { } /* end */
8980};
8981
Takashi Iwaia9111322011-05-02 11:30:18 +02008982static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
Jiang zhe17bba1b2008-06-04 12:11:07 +02008983 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8984 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8985 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8986 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8987 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8988 HDA_OUTPUT),
8989 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8990 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8991 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8992 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8993 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8994 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8995 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8996 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8997 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008998 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008999 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9000 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009001 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009002 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009003 { } /* end */
9004};
9005
Takashi Iwaia9111322011-05-02 11:30:18 +02009006static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009007 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9008 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9009 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9010 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9011 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9012 HDA_OUTPUT),
9013 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9014 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9015 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9016 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9017 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
9018 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9019 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9020 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9021 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009022 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009023 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
9024 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009025 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009026 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9027 { } /* end */
9028};
9029
Takashi Iwaia9111322011-05-02 11:30:18 +02009030static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02009031 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009032 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009033 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009034 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009035 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9036 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009037 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9038 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009039 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9040 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9041 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9042 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9043 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9044 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009045 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009046 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9047 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009048 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009049 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009050 { } /* end */
9051};
9052
Takashi Iwaia9111322011-05-02 11:30:18 +02009053static const struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009054 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009055 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009056 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009057 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009058 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9059 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9060 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9061 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9062 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9063 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9064 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9065 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9066 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9067 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9068 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009069 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009070 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009071 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009072};
Kailang Yangccc656c2006-10-17 12:32:26 +02009073
Takashi Iwaia9111322011-05-02 11:30:18 +02009074static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009075 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009076 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009077 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009078 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009079 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9080 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9081 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009082 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009083 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009084 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009085 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009086 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009087 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009088};
Kailang Yangccc656c2006-10-17 12:32:26 +02009089
Takashi Iwaia9111322011-05-02 11:30:18 +02009090static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009091 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9092 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009093 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009094 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009095 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009096 { } /* end */
9097};
9098
Takashi Iwaia9111322011-05-02 11:30:18 +02009099static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009100 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9101 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009102 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9103 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009104 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9105 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009106 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009107 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009108 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009109};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009110
Takashi Iwaia9111322011-05-02 11:30:18 +02009111static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009112 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9113 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9114 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9115 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9116 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9117 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9118 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009119 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9120 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009121 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02009122};
Kailang Yang272a5272007-05-14 11:00:38 +02009123
Takashi Iwaia9111322011-05-02 11:30:18 +02009124static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009125 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9126 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9127 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9128 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9129 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9130 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9131 { } /* end */
9132};
9133
Takashi Iwaia9111322011-05-02 11:30:18 +02009134static const struct hda_verb alc883_medion_wim2160_verbs[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009135 /* Unmute front mixer */
9136 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9137 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9138
9139 /* Set speaker pin to front mixer */
9140 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9141
9142 /* Init headphone pin */
9143 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9144 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9145 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9146 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9147
9148 { } /* end */
9149};
9150
9151/* toggle speaker-output according to the hp-jack state */
9152static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9153{
9154 struct alc_spec *spec = codec->spec;
9155
9156 spec->autocfg.hp_pins[0] = 0x1a;
9157 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009158 spec->automute = 1;
9159 spec->automute_mode = ALC_AUTOMUTE_AMP;
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009160}
9161
Takashi Iwaia9111322011-05-02 11:30:18 +02009162static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009163 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9164 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009165 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009166 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9167 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009168 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009169 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009170 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009171 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009172};
Tobin Davis2880a862007-08-07 11:50:26 +02009173
Takashi Iwaia9111322011-05-02 11:30:18 +02009174static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01009175 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009176 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009177 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9178 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009179 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9180 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9181 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009182 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009183 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9184 { } /* end */
9185};
9186
Takashi Iwaia9111322011-05-02 11:30:18 +02009187static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009188 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9189 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9190 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9191 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9192 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9193 0x0d, 1, 0x0, HDA_OUTPUT),
9194 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9195 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9196 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9197 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9198 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009199 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9200 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9201 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9202 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9203 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009204 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009205 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9206 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009207 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009208 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009209 { } /* end */
9210};
9211
Takashi Iwaia9111322011-05-02 11:30:18 +02009212static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009213 /* Output mixers */
9214 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9215 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9216 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9217 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9218 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9219 HDA_OUTPUT),
9220 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9221 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9222 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9223 /* Output switches */
9224 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9225 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9226 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9227 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009228 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9229 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009230 /* Input mixers */
9231 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9232 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9233 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9234 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9235 { } /* end */
9236};
9237
Takashi Iwaia9111322011-05-02 11:30:18 +02009238static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009239 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9240 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9241 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9242 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009243 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c2009-06-05 00:47:26 +02009244 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9245 { } /* end */
9246};
9247
Takashi Iwaia9111322011-05-02 11:30:18 +02009248static const struct hda_bind_ctls alc883_bind_cap_vol = {
Kailang Yange2757d52008-08-26 13:17:46 +02009249 .ops = &snd_hda_bind_vol,
9250 .values = {
9251 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9252 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9253 0
9254 },
9255};
9256
Takashi Iwaia9111322011-05-02 11:30:18 +02009257static const struct hda_bind_ctls alc883_bind_cap_switch = {
Kailang Yange2757d52008-08-26 13:17:46 +02009258 .ops = &snd_hda_bind_sw,
9259 .values = {
9260 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9261 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9262 0
9263 },
9264};
9265
Takashi Iwaia9111322011-05-02 11:30:18 +02009266static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009267 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9268 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9269 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9270 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9271 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9272 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009273 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009274 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009275 { } /* end */
9276};
9277
Takashi Iwaia9111322011-05-02 11:30:18 +02009278static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009279 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9280 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9281 {
9282 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9283 /* .name = "Capture Source", */
9284 .name = "Input Source",
9285 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009286 .info = alc_mux_enum_info,
9287 .get = alc_mux_enum_get,
9288 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009289 },
9290 { } /* end */
9291};
9292
Takashi Iwaia9111322011-05-02 11:30:18 +02009293static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009294 {
9295 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9296 .name = "Channel Mode",
9297 .info = alc_ch_mode_info,
9298 .get = alc_ch_mode_get,
9299 .put = alc_ch_mode_put,
9300 },
9301 { } /* end */
9302};
9303
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009304/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009305static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009306{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009307 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009308
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009309 spec->autocfg.hp_pins[0] = 0x15;
9310 spec->autocfg.speaker_pins[0] = 0x14;
9311 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009312 spec->automute = 1;
9313 spec->automute_mode = ALC_AUTOMUTE_AMP;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009314}
9315
Takashi Iwaia9111322011-05-02 11:30:18 +02009316static const struct hda_verb alc883_mitac_verbs[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009317 /* HP */
9318 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9319 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9320 /* Subwoofer */
9321 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9322 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9323
9324 /* enable unsolicited event */
9325 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9326 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9327
9328 { } /* end */
9329};
9330
Takashi Iwaia9111322011-05-02 11:30:18 +02009331static const struct hda_verb alc883_clevo_m540r_verbs[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309332 /* HP */
9333 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9334 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9335 /* Int speaker */
9336 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9337
9338 /* enable unsolicited event */
9339 /*
9340 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9341 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9342 */
9343
9344 { } /* end */
9345};
9346
Takashi Iwaia9111322011-05-02 11:30:18 +02009347static const struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009348 /* HP */
9349 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9350 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9351 /* Int speaker */
9352 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9353 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9354
9355 /* enable unsolicited event */
9356 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009357 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009358
9359 { } /* end */
9360};
9361
Takashi Iwaia9111322011-05-02 11:30:18 +02009362static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01009363 /* HP */
9364 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9365 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9366 /* Subwoofer */
9367 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9368 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9369
9370 /* enable unsolicited event */
9371 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9372
9373 { } /* end */
9374};
9375
Takashi Iwaia9111322011-05-02 11:30:18 +02009376static const struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009377 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9378 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9379
9380 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9381 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009382
David Heidelberger64a8be72009-06-08 16:15:18 +02009383/* Connect Line-Out side jack (SPDIF) to Side */
9384 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9385 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9386 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9387/* Connect Mic jack to CLFE */
9388 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9389 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9390 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9391/* Connect Line-in jack to Surround */
9392 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9393 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9394 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9395/* Connect HP out jack to Front */
9396 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9397 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9398 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009399
9400 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009401
9402 { } /* end */
9403};
9404
Takashi Iwaia9111322011-05-02 11:30:18 +02009405static const struct hda_verb alc883_lenovo_101e_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009406 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9407 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9408 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9409 { } /* end */
9410};
9411
Takashi Iwaia9111322011-05-02 11:30:18 +02009412static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009413 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9414 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9415 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9416 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9417 { } /* end */
9418};
9419
Takashi Iwaia9111322011-05-02 11:30:18 +02009420static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009421 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9423 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9424 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9425 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9426 { } /* end */
9427};
9428
Takashi Iwaia9111322011-05-02 11:30:18 +02009429static const struct hda_verb alc883_haier_w66_verbs[] = {
Kailang Yang189609a2007-08-20 11:31:23 +02009430 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9431 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9432
9433 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9434
9435 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9436 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9437 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9438 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9439 { } /* end */
9440};
9441
Takashi Iwaia9111322011-05-02 11:30:18 +02009442static const struct hda_verb alc888_lenovo_sky_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009443 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9444 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9445 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9446 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9447 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9448 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9449 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9450 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9451 { } /* end */
9452};
9453
Takashi Iwaia9111322011-05-02 11:30:18 +02009454static const struct hda_verb alc888_6st_dell_verbs[] = {
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009455 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9456 { }
9457};
9458
Takashi Iwaia9111322011-05-02 11:30:18 +02009459static const struct hda_verb alc883_vaiott_verbs[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009460 /* HP */
9461 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9462 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9463
9464 /* enable unsolicited event */
9465 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9466
9467 { } /* end */
9468};
9469
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009470static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009471{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009472 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009473
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009474 spec->autocfg.hp_pins[0] = 0x1b;
9475 spec->autocfg.speaker_pins[0] = 0x14;
9476 spec->autocfg.speaker_pins[1] = 0x16;
9477 spec->autocfg.speaker_pins[2] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02009478 spec->automute = 1;
9479 spec->automute_mode = ALC_AUTOMUTE_AMP;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009480}
9481
Takashi Iwaia9111322011-05-02 11:30:18 +02009482static const struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009483 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009484 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9485 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009486 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009487 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009488};
9489
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009490/*
9491 * 2ch mode
9492 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009493static const struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009494 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9495 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9496 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9497 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009498 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009499};
9500
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009501/*
9502 * 4ch mode
9503 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009504static const struct hda_verb alc888_3st_hp_4ch_init[] = {
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009505 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9506 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9507 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9508 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9509 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9510 { } /* end */
9511};
9512
9513/*
9514 * 6ch mode
9515 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009516static const struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009517 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9518 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009519 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009520 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9521 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009522 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9523 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009524};
9525
Takashi Iwaia9111322011-05-02 11:30:18 +02009526static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009527 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009528 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009529 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009530};
9531
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009532static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009533{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009534 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009535
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009536 spec->autocfg.hp_pins[0] = 0x1b;
9537 spec->autocfg.line_out_pins[0] = 0x14;
9538 spec->autocfg.speaker_pins[0] = 0x15;
9539 spec->automute = 1;
9540 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009541}
9542
Kailang Yang272a5272007-05-14 11:00:38 +02009543/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc427172010-11-29 07:42:59 +01009544static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009545{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009546 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009547
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009548 spec->autocfg.hp_pins[0] = 0x14;
9549 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009550 spec->automute = 1;
9551 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009552}
9553
Kailang Yangccc656c2006-10-17 12:32:26 +02009554/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009555#define alc883_targa_init_hook alc882_targa_init_hook
9556#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009557
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009558static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009559{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009560 struct alc_spec *spec = codec->spec;
9561
9562 spec->autocfg.hp_pins[0] = 0x15;
9563 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009564 spec->automute = 1;
9565 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009566}
9567
9568static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9569{
Takashi Iwaid922b512011-04-28 12:18:53 +02009570 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009571 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009572}
9573
9574static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009575 unsigned int res)
9576{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009577 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009578 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009579 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009580 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009581 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02009582 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009583 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009584 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009585}
9586
Jiang zhefb97dc62008-03-06 11:07:11 +01009587/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009588static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009589{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009590 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009591
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009592 spec->autocfg.hp_pins[0] = 0x14;
9593 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009594 spec->automute = 1;
9595 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhefb97dc62008-03-06 11:07:11 +01009596}
9597
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009598static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009599{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009600 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009601
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009602 spec->autocfg.hp_pins[0] = 0x1b;
9603 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009604 spec->automute = 1;
9605 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang189609a2007-08-20 11:31:23 +02009606}
9607
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009608static void alc883_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009609{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009610 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009611
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009612 spec->autocfg.hp_pins[0] = 0x1b;
9613 spec->autocfg.line_out_pins[0] = 0x14;
9614 spec->autocfg.speaker_pins[0] = 0x15;
9615 spec->automute = 1;
9616 spec->detect_line = 1;
9617 spec->automute_lines = 1;
9618 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009619}
9620
Takashi Iwai676a9b52007-08-16 15:23:35 +02009621/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009622static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009623{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009624 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009625
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009626 spec->autocfg.hp_pins[0] = 0x14;
9627 spec->autocfg.speaker_pins[0] = 0x15;
9628 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02009629 spec->automute = 1;
9630 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009631}
9632
Takashi Iwaia9111322011-05-02 11:30:18 +02009633static const struct hda_verb alc883_acer_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009634 /* HP Pin: output 0 (0x0c) */
9635 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9636 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9637 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9638 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009639 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9640 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009641 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009642 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9643 /* eanable EAPD on medion laptop */
9644 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9645 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009646 /* enable unsolicited event */
9647 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009648 { }
9649};
9650
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009651static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009652{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009653 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009654
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009655 spec->autocfg.hp_pins[0] = 0x1b;
9656 spec->autocfg.speaker_pins[0] = 0x14;
9657 spec->autocfg.speaker_pins[1] = 0x15;
9658 spec->autocfg.speaker_pins[2] = 0x16;
9659 spec->autocfg.speaker_pins[3] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009660 spec->automute = 1;
9661 spec->automute_mode = ALC_AUTOMUTE_AMP;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009662}
9663
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009664static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009665{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009666 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009667
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009668 spec->autocfg.hp_pins[0] = 0x1b;
9669 spec->autocfg.speaker_pins[0] = 0x14;
9670 spec->autocfg.speaker_pins[1] = 0x15;
9671 spec->autocfg.speaker_pins[2] = 0x16;
9672 spec->autocfg.speaker_pins[3] = 0x17;
9673 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02009674 spec->automute = 1;
9675 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009676}
9677
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009678static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009679{
9680 struct alc_spec *spec = codec->spec;
9681
9682 spec->autocfg.hp_pins[0] = 0x15;
9683 spec->autocfg.speaker_pins[0] = 0x14;
9684 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009685 spec->automute = 1;
9686 spec->automute_mode = ALC_AUTOMUTE_AMP;
Guido Günther3e1647c2009-06-05 00:47:26 +02009687}
9688
Takashi Iwaia9111322011-05-02 11:30:18 +02009689static const struct hda_verb alc888_asus_m90v_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009690 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9691 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9692 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9693 /* enable unsolicited event */
9694 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9695 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9696 { } /* end */
9697};
9698
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009699static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009700{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009701 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009702
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009703 spec->autocfg.hp_pins[0] = 0x1b;
9704 spec->autocfg.speaker_pins[0] = 0x14;
9705 spec->autocfg.speaker_pins[1] = 0x15;
9706 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009707 spec->ext_mic.pin = 0x18;
9708 spec->int_mic.pin = 0x19;
9709 spec->ext_mic.mux_idx = 0;
9710 spec->int_mic.mux_idx = 1;
9711 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +02009712 spec->automute = 1;
9713 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009714}
9715
Takashi Iwaia9111322011-05-02 11:30:18 +02009716static const struct hda_verb alc888_asus_eee1601_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009717 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9718 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9719 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9720 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9721 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9722 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9723 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9724 /* enable unsolicited event */
9725 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9726 { } /* end */
9727};
9728
Kailang Yange2757d52008-08-26 13:17:46 +02009729static void alc883_eee1601_inithook(struct hda_codec *codec)
9730{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009731 struct alc_spec *spec = codec->spec;
9732
9733 spec->autocfg.hp_pins[0] = 0x14;
9734 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02009735 alc_hp_automute(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009736}
9737
Takashi Iwaia9111322011-05-02 11:30:18 +02009738static const struct hda_verb alc889A_mb31_verbs[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009739 /* Init rear pin (used as headphone output) */
9740 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9741 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9742 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9743 /* Init line pin (used as output in 4ch and 6ch mode) */
9744 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9745 /* Init line 2 pin (used as headphone out by default) */
9746 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9747 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9748 { } /* end */
9749};
9750
9751/* Mute speakers according to the headphone jack state */
9752static void alc889A_mb31_automute(struct hda_codec *codec)
9753{
9754 unsigned int present;
9755
9756 /* Mute only in 2ch or 4ch mode */
9757 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9758 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009759 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009760 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9761 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9762 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9763 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9764 }
9765}
9766
9767static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9768{
9769 if ((res >> 26) == ALC880_HP_EVENT)
9770 alc889A_mb31_automute(codec);
9771}
9772
Takashi Iwai49535502009-06-30 15:28:30 +02009773
Takashi Iwaicb53c622007-08-10 17:21:45 +02009774#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02009775#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009776#endif
9777
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02009778static const hda_nid_t alc883_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009779 ALC1200_DIGOUT_NID, 0,
9780};
9781
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02009782static const hda_nid_t alc1200_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009783 ALC883_DIGOUT_NID, 0,
9784};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009785
9786/*
9787 * configuration and preset
9788 */
Takashi Iwaiea734962011-01-17 11:29:34 +01009789static const char * const alc882_models[ALC882_MODEL_LAST] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009790 [ALC882_3ST_DIG] = "3stack-dig",
9791 [ALC882_6ST_DIG] = "6stack-dig",
9792 [ALC882_ARIMA] = "arima",
9793 [ALC882_W2JC] = "w2jc",
9794 [ALC882_TARGA] = "targa",
9795 [ALC882_ASUS_A7J] = "asus-a7j",
9796 [ALC882_ASUS_A7M] = "asus-a7m",
9797 [ALC885_MACPRO] = "macpro",
9798 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009799 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009800 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +02009801 [ALC885_MBP3] = "mbp3",
9802 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009803 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02009804 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009805 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9806 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02009807 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009808 [ALC883_TARGA_DIG] = "targa-dig",
9809 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009810 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009811 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009812 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009813 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009814 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009815 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009816 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009817 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009818 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009819 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009820 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009821 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9822 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009823 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009824 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009825 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009826 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009827 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309828 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009829 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009830 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009831 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009832 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009833 [ALC889A_INTEL] = "intel-alc889a",
9834 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009835 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009836 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009837 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02009838 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009839};
9840
Takashi Iwaia9111322011-05-02 11:30:18 +02009841static const struct snd_pci_quirk alc882_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009842 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9843
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009844 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009845 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009846 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009847 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9848 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009849 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009850 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9851 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009852 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009853 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009854 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9855 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009856 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9857 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02009858 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9859 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009860 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009861 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009862 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009863 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009864 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9865 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009866 /* default Acer -- disabled as it causes more problems.
9867 * model=auto should work fine now
9868 */
9869 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02009870
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009871 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02009872
Lucas De Marchi25985ed2011-03-30 22:57:33 -03009873 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009874 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9875 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009876 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009877 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009878 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02009879
9880 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9881 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9882 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009883 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02009884 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9885 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9886 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009887 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009888 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009889 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009890 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02009891
9892 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009893 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009894 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009895 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009896 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9897 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009898 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009899 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwaiebb47242011-05-02 10:37:29 +02009900 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009901
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009902 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9903 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9904 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009905 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009906 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +02009907 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009908 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009909 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009910 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9911 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9912 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9913 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9914 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9915 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009916 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009917 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9918 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9919 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009920 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009921 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009922 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9923 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009924 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009925 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009926 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009927 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009928 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009929 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009930 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009931 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009932 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009933
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009934 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009935 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009936 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9937 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309938 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009939 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009940 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009941 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009942 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009943 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009944 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009945 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009946 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009947 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009948 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009949 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9950 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009951 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +01009952 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009953 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009954 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009955
Jiang zhe17bba1b2008-06-04 12:11:07 +02009956 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9957 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009958 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009959 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9960 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9961 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009962 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009963
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009964 {}
9965};
9966
Takashi Iwai49535502009-06-30 15:28:30 +02009967/* codec SSID table for Intel Mac */
Takashi Iwaia9111322011-05-02 11:30:18 +02009968static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009969 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9970 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9971 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9972 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9973 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9974 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9975 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009976 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009977 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009978 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009979 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +02009980 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9981 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9982 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009983 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +02009984 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009985 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009986 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9987 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +02009988 */
9989 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009990 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009991 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +02009992 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009993};
9994
Takashi Iwaia9111322011-05-02 11:30:18 +02009995static const struct alc_config_preset alc882_presets[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009996 [ALC882_3ST_DIG] = {
9997 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009998 .init_verbs = { alc882_base_init_verbs,
9999 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010000 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10001 .dac_nids = alc882_dac_nids,
10002 .dig_out_nid = ALC882_DIGOUT_NID,
10003 .dig_in_nid = ALC882_DIGIN_NID,
10004 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10005 .channel_mode = alc882_ch_modes,
10006 .need_dac_fix = 1,
10007 .input_mux = &alc882_capture_source,
10008 },
10009 [ALC882_6ST_DIG] = {
10010 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010011 .init_verbs = { alc882_base_init_verbs,
10012 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010013 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10014 .dac_nids = alc882_dac_nids,
10015 .dig_out_nid = ALC882_DIGOUT_NID,
10016 .dig_in_nid = ALC882_DIGIN_NID,
10017 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10018 .channel_mode = alc882_sixstack_modes,
10019 .input_mux = &alc882_capture_source,
10020 },
10021 [ALC882_ARIMA] = {
10022 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010023 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10024 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010025 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10026 .dac_nids = alc882_dac_nids,
10027 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10028 .channel_mode = alc882_sixstack_modes,
10029 .input_mux = &alc882_capture_source,
10030 },
10031 [ALC882_W2JC] = {
10032 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010033 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10034 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010035 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10036 .dac_nids = alc882_dac_nids,
10037 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10038 .channel_mode = alc880_threestack_modes,
10039 .need_dac_fix = 1,
10040 .input_mux = &alc882_capture_source,
10041 .dig_out_nid = ALC882_DIGOUT_NID,
10042 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010043 [ALC885_MBA21] = {
10044 .mixers = { alc885_mba21_mixer },
10045 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
10046 .num_dacs = 2,
10047 .dac_nids = alc882_dac_nids,
10048 .channel_mode = alc885_mba21_ch_modes,
10049 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10050 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010051 .unsol_event = alc_sku_unsol_event,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010052 .setup = alc885_mba21_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010053 .init_hook = alc_hp_automute,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010054 },
Takashi Iwai49535502009-06-30 15:28:30 +020010055 [ALC885_MBP3] = {
10056 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
10057 .init_verbs = { alc885_mbp3_init_verbs,
10058 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010059 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +020010060 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010061 .hp_nid = 0x04,
10062 .channel_mode = alc885_mbp_4ch_modes,
10063 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +020010064 .input_mux = &alc882_capture_source,
10065 .dig_out_nid = ALC882_DIGOUT_NID,
10066 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010067 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010068 .setup = alc885_mbp3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010069 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010070 },
10071 [ALC885_MB5] = {
10072 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
10073 .init_verbs = { alc885_mb5_init_verbs,
10074 alc880_gpio1_init_verbs },
10075 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10076 .dac_nids = alc882_dac_nids,
10077 .channel_mode = alc885_mb5_6ch_modes,
10078 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10079 .input_mux = &mb5_capture_source,
10080 .dig_out_nid = ALC882_DIGOUT_NID,
10081 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010082 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010083 .setup = alc885_mb5_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010084 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010085 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010086 [ALC885_MACMINI3] = {
10087 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10088 .init_verbs = { alc885_macmini3_init_verbs,
10089 alc880_gpio1_init_verbs },
10090 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10091 .dac_nids = alc882_dac_nids,
10092 .channel_mode = alc885_macmini3_6ch_modes,
10093 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10094 .input_mux = &macmini3_capture_source,
10095 .dig_out_nid = ALC882_DIGOUT_NID,
10096 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010097 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010098 .setup = alc885_macmini3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010099 .init_hook = alc_hp_automute,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010100 },
Takashi Iwai49535502009-06-30 15:28:30 +020010101 [ALC885_MACPRO] = {
10102 .mixers = { alc882_macpro_mixer },
10103 .init_verbs = { alc882_macpro_init_verbs },
10104 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10105 .dac_nids = alc882_dac_nids,
10106 .dig_out_nid = ALC882_DIGOUT_NID,
10107 .dig_in_nid = ALC882_DIGIN_NID,
10108 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10109 .channel_mode = alc882_ch_modes,
10110 .input_mux = &alc882_capture_source,
10111 .init_hook = alc885_macpro_init_hook,
10112 },
10113 [ALC885_IMAC24] = {
10114 .mixers = { alc885_imac24_mixer },
10115 .init_verbs = { alc885_imac24_init_verbs },
10116 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10117 .dac_nids = alc882_dac_nids,
10118 .dig_out_nid = ALC882_DIGOUT_NID,
10119 .dig_in_nid = ALC882_DIGIN_NID,
10120 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10121 .channel_mode = alc882_ch_modes,
10122 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010123 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010124 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +020010125 .init_hook = alc885_imac24_init_hook,
10126 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010127 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010128 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010129 .init_verbs = { alc885_imac91_init_verbs,
10130 alc880_gpio1_init_verbs },
10131 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10132 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010133 .channel_mode = alc885_mba21_ch_modes,
10134 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10135 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010136 .dig_out_nid = ALC882_DIGOUT_NID,
10137 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010138 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010139 .setup = alc885_imac91_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010140 .init_hook = alc_hp_automute,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010141 },
Takashi Iwai49535502009-06-30 15:28:30 +020010142 [ALC882_TARGA] = {
10143 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010144 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010145 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010146 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10147 .dac_nids = alc882_dac_nids,
10148 .dig_out_nid = ALC882_DIGOUT_NID,
10149 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10150 .adc_nids = alc882_adc_nids,
10151 .capsrc_nids = alc882_capsrc_nids,
10152 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10153 .channel_mode = alc882_3ST_6ch_modes,
10154 .need_dac_fix = 1,
10155 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010156 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010157 .setup = alc882_targa_setup,
10158 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010159 },
10160 [ALC882_ASUS_A7J] = {
10161 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010162 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10163 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010164 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10165 .dac_nids = alc882_dac_nids,
10166 .dig_out_nid = ALC882_DIGOUT_NID,
10167 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10168 .adc_nids = alc882_adc_nids,
10169 .capsrc_nids = alc882_capsrc_nids,
10170 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10171 .channel_mode = alc882_3ST_6ch_modes,
10172 .need_dac_fix = 1,
10173 .input_mux = &alc882_capture_source,
10174 },
10175 [ALC882_ASUS_A7M] = {
10176 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010177 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10178 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +020010179 alc882_asus_a7m_verbs },
10180 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10181 .dac_nids = alc882_dac_nids,
10182 .dig_out_nid = ALC882_DIGOUT_NID,
10183 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10184 .channel_mode = alc880_threestack_modes,
10185 .need_dac_fix = 1,
10186 .input_mux = &alc882_capture_source,
10187 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010188 [ALC883_3ST_2ch_DIG] = {
10189 .mixers = { alc883_3ST_2ch_mixer },
10190 .init_verbs = { alc883_init_verbs },
10191 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10192 .dac_nids = alc883_dac_nids,
10193 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010194 .dig_in_nid = ALC883_DIGIN_NID,
10195 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10196 .channel_mode = alc883_3ST_2ch_modes,
10197 .input_mux = &alc883_capture_source,
10198 },
10199 [ALC883_3ST_6ch_DIG] = {
10200 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10201 .init_verbs = { alc883_init_verbs },
10202 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10203 .dac_nids = alc883_dac_nids,
10204 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010205 .dig_in_nid = ALC883_DIGIN_NID,
10206 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10207 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010208 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010209 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010210 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010211 [ALC883_3ST_6ch] = {
10212 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10213 .init_verbs = { alc883_init_verbs },
10214 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10215 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010216 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10217 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010218 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010219 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010220 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010221 [ALC883_3ST_6ch_INTEL] = {
10222 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10223 .init_verbs = { alc883_init_verbs },
10224 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10225 .dac_nids = alc883_dac_nids,
10226 .dig_out_nid = ALC883_DIGOUT_NID,
10227 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010228 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010229 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10230 .channel_mode = alc883_3ST_6ch_intel_modes,
10231 .need_dac_fix = 1,
10232 .input_mux = &alc883_3stack_6ch_intel,
10233 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010234 [ALC889A_INTEL] = {
10235 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010236 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10237 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010238 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10239 .dac_nids = alc883_dac_nids,
10240 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10241 .adc_nids = alc889_adc_nids,
10242 .dig_out_nid = ALC883_DIGOUT_NID,
10243 .dig_in_nid = ALC883_DIGIN_NID,
10244 .slave_dig_outs = alc883_slave_dig_outs,
10245 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10246 .channel_mode = alc889_8ch_intel_modes,
10247 .capsrc_nids = alc889_capsrc_nids,
10248 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010249 .setup = alc889_automute_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010250 .init_hook = alc_hp_automute,
10251 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010252 .need_dac_fix = 1,
10253 },
10254 [ALC889_INTEL] = {
10255 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10256 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010257 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010258 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10259 .dac_nids = alc883_dac_nids,
10260 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10261 .adc_nids = alc889_adc_nids,
10262 .dig_out_nid = ALC883_DIGOUT_NID,
10263 .dig_in_nid = ALC883_DIGIN_NID,
10264 .slave_dig_outs = alc883_slave_dig_outs,
10265 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10266 .channel_mode = alc889_8ch_intel_modes,
10267 .capsrc_nids = alc889_capsrc_nids,
10268 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010269 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010270 .init_hook = alc889_intel_init_hook,
Takashi Iwaid922b512011-04-28 12:18:53 +020010271 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010272 .need_dac_fix = 1,
10273 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010274 [ALC883_6ST_DIG] = {
10275 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10276 .init_verbs = { alc883_init_verbs },
10277 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10278 .dac_nids = alc883_dac_nids,
10279 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010280 .dig_in_nid = ALC883_DIGIN_NID,
10281 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10282 .channel_mode = alc883_sixstack_modes,
10283 .input_mux = &alc883_capture_source,
10284 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010285 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010286 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010287 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10288 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010289 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10290 .dac_nids = alc883_dac_nids,
10291 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010292 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10293 .channel_mode = alc883_3ST_6ch_modes,
10294 .need_dac_fix = 1,
10295 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010296 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010297 .setup = alc882_targa_setup,
10298 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010299 },
10300 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010301 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010302 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10303 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010304 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10305 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010306 .adc_nids = alc883_adc_nids_alt,
10307 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010308 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010309 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010310 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10311 .channel_mode = alc883_3ST_2ch_modes,
10312 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010313 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010314 .setup = alc882_targa_setup,
10315 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010316 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010317 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010318 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10319 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010320 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010321 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010322 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10323 .dac_nids = alc883_dac_nids,
10324 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10325 .adc_nids = alc883_adc_nids_rev,
10326 .capsrc_nids = alc883_capsrc_nids_rev,
10327 .dig_out_nid = ALC883_DIGOUT_NID,
10328 .dig_in_nid = ALC883_DIGIN_NID,
10329 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10330 .channel_mode = alc883_4ST_8ch_modes,
10331 .need_dac_fix = 1,
10332 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010333 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010334 .setup = alc882_targa_setup,
10335 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010336 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010337 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010338 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010339 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10340 * and the headphone jack. Turn this on and rely on the
10341 * standard mute methods whenever the user wants to turn
10342 * these outputs off.
10343 */
10344 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10345 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10346 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010347 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10348 .channel_mode = alc883_3ST_2ch_modes,
10349 .input_mux = &alc883_capture_source,
10350 },
Tobin Davis2880a862007-08-07 11:50:26 +020010351 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010352 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010353 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010354 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10355 .dac_nids = alc883_dac_nids,
10356 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010357 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10358 .channel_mode = alc883_3ST_2ch_modes,
10359 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010360 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010361 .setup = alc883_acer_aspire_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010362 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010363 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010364 [ALC888_ACER_ASPIRE_4930G] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +010010365 .mixers = { alc888_acer_aspire_4930g_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010366 alc883_chmode_mixer },
10367 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10368 alc888_acer_aspire_4930g_verbs },
10369 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10370 .dac_nids = alc883_dac_nids,
10371 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10372 .adc_nids = alc883_adc_nids_rev,
10373 .capsrc_nids = alc883_capsrc_nids_rev,
10374 .dig_out_nid = ALC883_DIGOUT_NID,
10375 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10376 .channel_mode = alc883_3ST_6ch_modes,
10377 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010378 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010379 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010380 ARRAY_SIZE(alc888_2_capture_sources),
10381 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010382 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010383 .setup = alc888_acer_aspire_4930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010384 .init_hook = alc_hp_automute,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010385 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010386 [ALC888_ACER_ASPIRE_6530G] = {
10387 .mixers = { alc888_acer_aspire_6530_mixer },
10388 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10389 alc888_acer_aspire_6530g_verbs },
10390 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10391 .dac_nids = alc883_dac_nids,
10392 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10393 .adc_nids = alc883_adc_nids_rev,
10394 .capsrc_nids = alc883_capsrc_nids_rev,
10395 .dig_out_nid = ALC883_DIGOUT_NID,
10396 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10397 .channel_mode = alc883_3ST_2ch_modes,
10398 .num_mux_defs =
10399 ARRAY_SIZE(alc888_2_capture_sources),
10400 .input_mux = alc888_acer_aspire_6530_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010401 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010402 .setup = alc888_acer_aspire_6530g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010403 .init_hook = alc_hp_automute,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010404 },
Hector Martin3b315d72009-06-02 10:54:19 +020010405 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010406 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010407 alc883_chmode_mixer },
10408 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010409 alc889_acer_aspire_8930g_verbs,
10410 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010411 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10412 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010413 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10414 .adc_nids = alc889_adc_nids,
10415 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010416 .dig_out_nid = ALC883_DIGOUT_NID,
10417 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10418 .channel_mode = alc883_3ST_6ch_modes,
10419 .need_dac_fix = 1,
10420 .const_channel_count = 6,
10421 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010422 ARRAY_SIZE(alc889_capture_sources),
10423 .input_mux = alc889_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010424 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010425 .setup = alc889_acer_aspire_8930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010426 .init_hook = alc_hp_automute,
Hector Martinf5de24b2009-12-20 22:51:31 +010010427#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010428 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010429#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010430 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010431 [ALC888_ACER_ASPIRE_7730G] = {
10432 .mixers = { alc883_3ST_6ch_mixer,
10433 alc883_chmode_mixer },
10434 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10435 alc888_acer_aspire_7730G_verbs },
10436 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10437 .dac_nids = alc883_dac_nids,
10438 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10439 .adc_nids = alc883_adc_nids_rev,
10440 .capsrc_nids = alc883_capsrc_nids_rev,
10441 .dig_out_nid = ALC883_DIGOUT_NID,
10442 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10443 .channel_mode = alc883_3ST_6ch_modes,
10444 .need_dac_fix = 1,
10445 .const_channel_count = 6,
10446 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010447 .unsol_event = alc_sku_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010448 .setup = alc888_acer_aspire_7730g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010449 .init_hook = alc_hp_automute,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010450 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010451 [ALC883_MEDION] = {
10452 .mixers = { alc883_fivestack_mixer,
10453 alc883_chmode_mixer },
10454 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010455 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010456 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10457 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010458 .adc_nids = alc883_adc_nids_alt,
10459 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010460 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010461 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10462 .channel_mode = alc883_sixstack_modes,
10463 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010464 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010465 [ALC883_MEDION_WIM2160] = {
10466 .mixers = { alc883_medion_wim2160_mixer },
10467 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10468 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10469 .dac_nids = alc883_dac_nids,
10470 .dig_out_nid = ALC883_DIGOUT_NID,
10471 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10472 .adc_nids = alc883_adc_nids,
10473 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10474 .channel_mode = alc883_3ST_2ch_modes,
10475 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010476 .unsol_event = alc_sku_unsol_event,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010477 .setup = alc883_medion_wim2160_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010478 .init_hook = alc_hp_automute,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010479 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010480 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010481 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010482 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10483 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10484 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010485 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10486 .channel_mode = alc883_3ST_2ch_modes,
10487 .input_mux = &alc883_capture_source,
10488 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010489 [ALC883_CLEVO_M540R] = {
10490 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10491 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10492 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10493 .dac_nids = alc883_dac_nids,
10494 .dig_out_nid = ALC883_DIGOUT_NID,
10495 .dig_in_nid = ALC883_DIGIN_NID,
10496 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10497 .channel_mode = alc883_3ST_6ch_clevo_modes,
10498 .need_dac_fix = 1,
10499 .input_mux = &alc883_capture_source,
10500 /* This machine has the hardware HP auto-muting, thus
10501 * we need no software mute via unsol event
10502 */
10503 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010504 [ALC883_CLEVO_M720] = {
10505 .mixers = { alc883_clevo_m720_mixer },
10506 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010507 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10508 .dac_nids = alc883_dac_nids,
10509 .dig_out_nid = ALC883_DIGOUT_NID,
10510 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10511 .channel_mode = alc883_3ST_2ch_modes,
10512 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010513 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010514 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010515 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010516 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010517 [ALC883_LENOVO_101E_2ch] = {
10518 .mixers = { alc883_lenovo_101e_2ch_mixer},
10519 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10520 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10521 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010522 .adc_nids = alc883_adc_nids_alt,
10523 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010524 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010525 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10526 .channel_mode = alc883_3ST_2ch_modes,
10527 .input_mux = &alc883_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010528 .setup = alc883_lenovo_101e_setup,
10529 .unsol_event = alc_sku_unsol_event,
10530 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010531 },
Kailang Yang272a5272007-05-14 11:00:38 +020010532 [ALC883_LENOVO_NB0763] = {
10533 .mixers = { alc883_lenovo_nb0763_mixer },
10534 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10535 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10536 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010537 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10538 .channel_mode = alc883_3ST_2ch_modes,
10539 .need_dac_fix = 1,
10540 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010541 .unsol_event = alc_sku_unsol_event,
Takashi Iwaidc427172010-11-29 07:42:59 +010010542 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010543 .init_hook = alc_hp_automute,
Kailang Yang272a5272007-05-14 11:00:38 +020010544 },
10545 [ALC888_LENOVO_MS7195_DIG] = {
10546 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10547 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10548 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10549 .dac_nids = alc883_dac_nids,
10550 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010551 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10552 .channel_mode = alc883_3ST_6ch_modes,
10553 .need_dac_fix = 1,
10554 .input_mux = &alc883_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010555 .unsol_event = alc_sku_unsol_event,
10556 .setup = alc888_lenovo_ms7195_setup,
10557 .init_hook = alc_inithook,
Kailang Yang189609a2007-08-20 11:31:23 +020010558 },
10559 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010560 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010561 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10562 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10563 .dac_nids = alc883_dac_nids,
10564 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010565 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10566 .channel_mode = alc883_3ST_2ch_modes,
10567 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010568 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010569 .setup = alc883_haier_w66_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010570 .init_hook = alc_hp_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010571 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010572 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010573 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010574 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010575 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10576 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010577 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10578 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010579 .need_dac_fix = 1,
10580 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010581 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010582 .setup = alc888_3st_hp_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010583 .init_hook = alc_hp_automute,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010584 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010585 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010586 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010587 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10588 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10589 .dac_nids = alc883_dac_nids,
10590 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010591 .dig_in_nid = ALC883_DIGIN_NID,
10592 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10593 .channel_mode = alc883_sixstack_modes,
10594 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010595 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010596 .setup = alc888_6st_dell_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010597 .init_hook = alc_hp_automute,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010598 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010599 [ALC883_MITAC] = {
10600 .mixers = { alc883_mitac_mixer },
10601 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10602 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10603 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010604 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10605 .channel_mode = alc883_3ST_2ch_modes,
10606 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010607 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010608 .setup = alc883_mitac_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010609 .init_hook = alc_hp_automute,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010610 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010611 [ALC883_FUJITSU_PI2515] = {
10612 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10613 .init_verbs = { alc883_init_verbs,
10614 alc883_2ch_fujitsu_pi2515_verbs},
10615 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10616 .dac_nids = alc883_dac_nids,
10617 .dig_out_nid = ALC883_DIGOUT_NID,
10618 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10619 .channel_mode = alc883_3ST_2ch_modes,
10620 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010621 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010622 .setup = alc883_2ch_fujitsu_pi2515_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010623 .init_hook = alc_hp_automute,
Jiang zhefb97dc62008-03-06 11:07:11 +010010624 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010625 [ALC888_FUJITSU_XA3530] = {
10626 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10627 .init_verbs = { alc883_init_verbs,
10628 alc888_fujitsu_xa3530_verbs },
10629 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10630 .dac_nids = alc883_dac_nids,
10631 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10632 .adc_nids = alc883_adc_nids_rev,
10633 .capsrc_nids = alc883_capsrc_nids_rev,
10634 .dig_out_nid = ALC883_DIGOUT_NID,
10635 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10636 .channel_mode = alc888_4ST_8ch_intel_modes,
10637 .num_mux_defs =
10638 ARRAY_SIZE(alc888_2_capture_sources),
10639 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010640 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010641 .setup = alc888_fujitsu_xa3530_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010642 .init_hook = alc_hp_automute,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010643 },
Kailang Yange2757d52008-08-26 13:17:46 +020010644 [ALC888_LENOVO_SKY] = {
10645 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10646 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10647 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10648 .dac_nids = alc883_dac_nids,
10649 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010650 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10651 .channel_mode = alc883_sixstack_modes,
10652 .need_dac_fix = 1,
10653 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010654 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010655 .setup = alc888_lenovo_sky_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010656 .init_hook = alc_hp_automute,
Kailang Yange2757d52008-08-26 13:17:46 +020010657 },
10658 [ALC888_ASUS_M90V] = {
10659 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10660 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10661 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10662 .dac_nids = alc883_dac_nids,
10663 .dig_out_nid = ALC883_DIGOUT_NID,
10664 .dig_in_nid = ALC883_DIGIN_NID,
10665 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10666 .channel_mode = alc883_3ST_6ch_modes,
10667 .need_dac_fix = 1,
10668 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010669 .unsol_event = alc_sku_unsol_event,
10670 .setup = alc883_mode2_setup,
10671 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010672 },
10673 [ALC888_ASUS_EEE1601] = {
10674 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010675 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010676 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10677 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10678 .dac_nids = alc883_dac_nids,
10679 .dig_out_nid = ALC883_DIGOUT_NID,
10680 .dig_in_nid = ALC883_DIGIN_NID,
10681 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10682 .channel_mode = alc883_3ST_2ch_modes,
10683 .need_dac_fix = 1,
10684 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010685 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010686 .init_hook = alc883_eee1601_inithook,
10687 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010688 [ALC1200_ASUS_P5Q] = {
10689 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10690 .init_verbs = { alc883_init_verbs },
10691 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10692 .dac_nids = alc883_dac_nids,
10693 .dig_out_nid = ALC1200_DIGOUT_NID,
10694 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010695 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010696 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10697 .channel_mode = alc883_sixstack_modes,
10698 .input_mux = &alc883_capture_source,
10699 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010700 [ALC889A_MB31] = {
10701 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10702 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10703 alc880_gpio1_init_verbs },
10704 .adc_nids = alc883_adc_nids,
10705 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010706 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010707 .dac_nids = alc883_dac_nids,
10708 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10709 .channel_mode = alc889A_mb31_6ch_modes,
10710 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10711 .input_mux = &alc889A_mb31_capture_source,
10712 .dig_out_nid = ALC883_DIGOUT_NID,
10713 .unsol_event = alc889A_mb31_unsol_event,
10714 .init_hook = alc889A_mb31_automute,
10715 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010716 [ALC883_SONY_VAIO_TT] = {
10717 .mixers = { alc883_vaiott_mixer },
10718 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10719 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10720 .dac_nids = alc883_dac_nids,
10721 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10722 .channel_mode = alc883_3ST_2ch_modes,
10723 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010724 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010725 .setup = alc883_vaiott_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010726 .init_hook = alc_hp_automute,
Guido Günther3e1647c2009-06-05 00:47:26 +020010727 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010728};
10729
10730
10731/*
Takashi Iwai49535502009-06-30 15:28:30 +020010732 * Pin config fixes
10733 */
10734enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010735 PINFIX_ABIT_AW9D_MAX,
David Henningsson32eea382011-03-04 13:37:50 +010010736 PINFIX_LENOVO_Y530,
Takashi Iwai954a29c2010-07-30 10:55:44 +020010737 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010738 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai49535502009-06-30 15:28:30 +020010739};
10740
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010741static const struct alc_fixup alc882_fixups[] = {
10742 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010743 .type = ALC_FIXUP_PINS,
10744 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010745 { 0x15, 0x01080104 }, /* side */
10746 { 0x16, 0x01011012 }, /* rear */
10747 { 0x17, 0x01016011 }, /* clfe */
10748 { }
10749 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010750 },
David Henningsson32eea382011-03-04 13:37:50 +010010751 [PINFIX_LENOVO_Y530] = {
10752 .type = ALC_FIXUP_PINS,
10753 .v.pins = (const struct alc_pincfg[]) {
10754 { 0x15, 0x99130112 }, /* rear int speakers */
10755 { 0x16, 0x99130111 }, /* subwoofer */
10756 { }
10757 }
10758 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010759 [PINFIX_PB_M5210] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010760 .type = ALC_FIXUP_VERBS,
10761 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010762 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10763 {}
10764 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010765 },
David Henningssonc3d226a2010-10-14 15:42:08 +020010766 [PINFIX_ACER_ASPIRE_7736] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010767 .type = ALC_FIXUP_SKU,
10768 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonc3d226a2010-10-14 15:42:08 +020010769 },
Takashi Iwai49535502009-06-30 15:28:30 +020010770};
10771
Takashi Iwaia9111322011-05-02 11:30:18 +020010772static const struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010773 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
David Henningsson32eea382011-03-04 13:37:50 +010010774 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
Takashi Iwai49535502009-06-30 15:28:30 +020010775 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020010776 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai49535502009-06-30 15:28:30 +020010777 {}
10778};
10779
10780/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010781 * BIOS auto configuration
10782 */
Takashi Iwaif970de22011-07-06 17:39:59 +020010783static void alc_auto_init_input_src(struct hda_codec *codec)
Takashi Iwai49535502009-06-30 15:28:30 +020010784{
10785 struct alc_spec *spec = codec->spec;
10786 int c;
10787
Takashi Iwaif970de22011-07-06 17:39:59 +020010788 if (spec->dual_adc_switch)
10789 return;
10790
Takashi Iwai49535502009-06-30 15:28:30 +020010791 for (c = 0; c < spec->num_adc_nids; c++) {
Takashi Iwaif970de22011-07-06 17:39:59 +020010792 hda_nid_t nid;
Takashi Iwai49535502009-06-30 15:28:30 +020010793 unsigned int mux_idx;
10794 const struct hda_input_mux *imux;
10795 int conns, mute, idx, item;
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020010796 unsigned int wid_type;
Takashi Iwai49535502009-06-30 15:28:30 +020010797
Takashi Iwaif970de22011-07-06 17:39:59 +020010798 nid = spec->capsrc_nids ?
10799 spec->capsrc_nids[c] : spec->adc_nids[c];
Takashi Iwai10696aa2011-04-07 12:46:45 +020010800 /* mute ADC */
Takashi Iwai4f574b72011-06-27 16:17:07 +020010801 if (query_amp_caps(codec, spec->adc_nids[c], HDA_INPUT) &
10802 AC_AMPCAP_MUTE)
10803 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
Takashi Iwai10696aa2011-04-07 12:46:45 +020010804 AC_VERB_SET_AMP_GAIN_MUTE,
10805 AMP_IN_MUTE(0));
Takashi Iwai4f574b72011-06-27 16:17:07 +020010806 else if (query_amp_caps(codec, nid, HDA_OUTPUT) &
10807 AC_AMPCAP_MUTE)
10808 snd_hda_codec_write(codec, nid, 0,
10809 AC_VERB_SET_AMP_GAIN_MUTE,
10810 AMP_OUT_MUTE);
Takashi Iwai10696aa2011-04-07 12:46:45 +020010811
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020010812 conns = snd_hda_get_conn_list(codec, nid, NULL);
10813 if (conns <= 0)
Takashi Iwai49535502009-06-30 15:28:30 +020010814 continue;
10815 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10816 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010817 if (!imux->num_items && mux_idx > 0)
10818 imux = &spec->input_mux[0];
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020010819 wid_type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai49535502009-06-30 15:28:30 +020010820 for (idx = 0; idx < conns; idx++) {
10821 /* if the current connection is the selected one,
10822 * unmute it as default - otherwise mute it
10823 */
10824 mute = AMP_IN_MUTE(idx);
10825 for (item = 0; item < imux->num_items; item++) {
10826 if (imux->items[item].index == idx) {
10827 if (spec->cur_mux[c] == item)
10828 mute = AMP_IN_UNMUTE(idx);
10829 break;
10830 }
10831 }
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020010832 /* initialize the mute status if mute-amp is present */
10833 if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010834 snd_hda_codec_write(codec, nid, 0,
10835 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020010836 mute);
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020010837 if (wid_type == AC_WID_AUD_SEL &&
10838 mute != AMP_IN_MUTE(idx))
Takashi Iwai49535502009-06-30 15:28:30 +020010839 snd_hda_codec_write(codec, nid, 0,
10840 AC_VERB_SET_CONNECT_SEL,
10841 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010842 }
10843 }
10844}
10845
Takashi Iwai49535502009-06-30 15:28:30 +020010846/* add mic boosts if needed */
10847static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010848{
10849 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010850 struct auto_pin_cfg *cfg = &spec->autocfg;
David Henningsson5322bf22011-01-05 11:03:56 +010010851 int i, err;
Takashi Iwai53e8c322010-12-17 15:23:41 +010010852 int type_idx = 0;
Takashi Iwai49535502009-06-30 15:28:30 +020010853 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010010854 const char *prev_label = NULL;
Takashi Iwai49535502009-06-30 15:28:30 +020010855
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010856 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020010857 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010858 break;
10859 nid = cfg->inputs[i].pin;
10860 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
David Henningsson5322bf22011-01-05 11:03:56 +010010861 const char *label;
10862 char boost_label[32];
10863
10864 label = hda_get_autocfg_input_label(codec, cfg, i);
10865 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai53e8c322010-12-17 15:23:41 +010010866 type_idx++;
10867 else
10868 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +010010869 prev_label = label;
10870
10871 snprintf(boost_label, sizeof(boost_label),
10872 "%s Boost Volume", label);
10873 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10874 boost_label, type_idx,
Takashi Iwai49535502009-06-30 15:28:30 +020010875 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010876 if (err < 0)
10877 return err;
10878 }
Takashi Iwai49535502009-06-30 15:28:30 +020010879 }
10880 return 0;
10881}
10882
10883/* almost identical with ALC880 parser... */
10884static int alc882_parse_auto_config(struct hda_codec *codec)
10885{
10886 struct alc_spec *spec = codec->spec;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020010887 static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010888 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010889
Takashi Iwai05f5f472009-08-25 13:10:18 +020010890 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10891 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010892 if (err < 0)
10893 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010894 if (!spec->autocfg.line_outs)
10895 return 0; /* can't find valid BIOS pin config */
10896
Takashi Iwai343a04b2011-07-06 14:28:39 +020010897 err = alc_auto_fill_dac_nids(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010898 if (err < 0)
10899 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010900 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020010901 if (err < 0)
10902 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010903 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010904 if (err < 0)
10905 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010906 err = alc_auto_create_hp_out(codec);
Takashi Iwai489008c2010-04-07 09:06:00 +020010907 if (err < 0)
10908 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010909 err = alc_auto_create_speaker_out(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010910 if (err < 0)
10911 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020010912 err = alc_auto_create_input_ctls(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010913 if (err < 0)
10914 return err;
10915
10916 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10917
Takashi Iwai757899a2010-07-30 10:48:14 +020010918 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010919
10920 if (spec->kctls.list)
10921 add_mixer(spec, spec->kctls.list);
10922
Takashi Iwai05f5f472009-08-25 13:10:18 +020010923 spec->num_mux_defs = 1;
10924 spec->input_mux = &spec->private_imux[0];
10925
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020010926 if (!spec->dual_adc_switch)
10927 alc_remove_invalid_adc_nids(codec);
10928
Kailang Yang6227cdc2010-02-25 08:36:52 +010010929 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010930
10931 err = alc_auto_add_mic_boost(codec);
10932 if (err < 0)
10933 return err;
10934
Takashi Iwai776e1842007-08-29 15:07:11 +020010935 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010936}
10937
10938/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010939static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010940{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010941 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010942 alc_auto_init_multi_out(codec);
10943 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020010944 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020010945 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010946 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010947 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010948 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010949}
10950
Takashi Iwai49535502009-06-30 15:28:30 +020010951static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010952{
10953 struct alc_spec *spec;
10954 int err, board_config;
10955
10956 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10957 if (spec == NULL)
10958 return -ENOMEM;
10959
10960 codec->spec = spec;
10961
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020010962 spec->mixer_nid = 0x0b;
10963
Takashi Iwai49535502009-06-30 15:28:30 +020010964 switch (codec->vendor_id) {
10965 case 0x10ec0882:
10966 case 0x10ec0885:
10967 break;
10968 default:
10969 /* ALC883 and variants */
10970 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10971 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010972 }
10973
Takashi Iwai49535502009-06-30 15:28:30 +020010974 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10975 alc882_models,
10976 alc882_cfg_tbl);
10977
10978 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10979 board_config = snd_hda_check_board_codec_sid_config(codec,
10980 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10981
10982 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010983 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020010984 codec->chip_name);
10985 board_config = ALC882_AUTO;
10986 }
10987
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010988 if (board_config == ALC882_AUTO) {
10989 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
10990 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
10991 }
Takashi Iwai49535502009-06-30 15:28:30 +020010992
David Henningsson90622912010-10-14 14:50:18 +020010993 alc_auto_parse_customize_define(codec);
10994
Takashi Iwai49535502009-06-30 15:28:30 +020010995 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010996 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020010997 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010998 if (err < 0) {
10999 alc_free(codec);
11000 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011001 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011002 printk(KERN_INFO
11003 "hda_codec: Cannot set up configuration "
11004 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020011005 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011006 }
11007 }
11008
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011009 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020011010 err = snd_hda_attach_beep_device(codec, 0x1);
11011 if (err < 0) {
11012 alc_free(codec);
11013 return err;
11014 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011015 }
11016
Takashi Iwai49535502009-06-30 15:28:30 +020011017 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011018 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011019
Takashi Iwai49535502009-06-30 15:28:30 +020011020 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020011021 alc_auto_fill_adc_caps(codec);
11022 alc_remove_invalid_adc_nids(codec);
Kailang Yang2f893282008-05-27 12:14:47 +020011023 }
11024
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011025 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011026
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011027 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011028 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011029
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011030 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011031
Takashi Iwai2134ea42008-01-10 16:53:55 +010011032 spec->vmaster_nid = 0x0c;
11033
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011034 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020011035 if (board_config == ALC882_AUTO)
11036 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011037
11038 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011039#ifdef CONFIG_SND_HDA_POWER_SAVE
11040 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020011041 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011042#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011043
11044 return 0;
11045}
11046
Takashi Iwai49535502009-06-30 15:28:30 +020011047
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011048/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011049 * ALC262 support
11050 */
11051
11052#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11053#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11054
11055#define alc262_dac_nids alc260_dac_nids
11056#define alc262_adc_nids alc882_adc_nids
11057#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011058#define alc262_capsrc_nids alc882_capsrc_nids
11059#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011060
11061#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011062#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011063
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011064static const hda_nid_t alc262_dmic_adc_nids[1] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011065 /* ADC0 */
11066 0x09
11067};
11068
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011069static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
Kailang Yang4e555fe2008-08-26 13:05:55 +020011070
Takashi Iwaia9111322011-05-02 11:30:18 +020011071static const struct snd_kcontrol_new alc262_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011072 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11073 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11074 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11075 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11076 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11077 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11078 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11079 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011080 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011081 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11082 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011083 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011084 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11085 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11086 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11087 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011088 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011089};
11090
Takashi Iwaice875f02008-01-28 18:17:43 +010011091/* update HP, line and mono-out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011092#define alc262_hp_master_update alc260_hp_master_update
Takashi Iwaice875f02008-01-28 18:17:43 +010011093
Takashi Iwaie9427962011-04-28 15:46:07 +020011094static void alc262_hp_bpc_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011095{
11096 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011097
Takashi Iwaie9427962011-04-28 15:46:07 +020011098 spec->autocfg.hp_pins[0] = 0x1b;
11099 spec->autocfg.speaker_pins[0] = 0x16;
11100 spec->automute = 1;
11101 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011102}
11103
Takashi Iwaie9427962011-04-28 15:46:07 +020011104static void alc262_hp_wildwest_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011105{
11106 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011107
Takashi Iwaie9427962011-04-28 15:46:07 +020011108 spec->autocfg.hp_pins[0] = 0x15;
11109 spec->autocfg.speaker_pins[0] = 0x16;
11110 spec->automute = 1;
11111 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011112}
11113
Takashi Iwaib72519b2009-05-08 14:31:55 +020011114#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011115#define alc262_hp_master_sw_put alc260_hp_master_sw_put
Takashi Iwaice875f02008-01-28 18:17:43 +010011116
Takashi Iwaib72519b2009-05-08 14:31:55 +020011117#define ALC262_HP_MASTER_SWITCH \
11118 { \
11119 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11120 .name = "Master Playback Switch", \
11121 .info = snd_ctl_boolean_mono_info, \
11122 .get = alc262_hp_master_sw_get, \
11123 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011124 }, \
11125 { \
11126 .iface = NID_MAPPING, \
11127 .name = "Master Playback Switch", \
11128 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011129 }
11130
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011131
Takashi Iwaia9111322011-05-02 11:30:18 +020011132static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011133 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011134 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11135 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11136 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011137 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11138 HDA_OUTPUT),
11139 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11140 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011141 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11142 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011143 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011144 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11145 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011146 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011147 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11148 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11149 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11150 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011151 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11152 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11153 { } /* end */
11154};
11155
Takashi Iwaia9111322011-05-02 11:30:18 +020011156static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011157 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011158 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11159 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11160 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11161 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011162 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11163 HDA_OUTPUT),
11164 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11165 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011166 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11167 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011168 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011169 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11170 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11171 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11172 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011173 { } /* end */
11174};
11175
Takashi Iwaia9111322011-05-02 11:30:18 +020011176static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010011177 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11178 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011179 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011180 { } /* end */
11181};
11182
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011183/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011184static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011185{
11186 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011187
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011188 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011189 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020011190 spec->automute = 1;
11191 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011192}
11193
Takashi Iwaia9111322011-05-02 11:30:18 +020011194static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011195 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11196 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011197 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11199 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11200 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011201 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011202 { } /* end */
11203};
11204
Takashi Iwaia9111322011-05-02 11:30:18 +020011205static const struct hda_verb alc262_hp_t5735_verbs[] = {
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011206 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11207 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11208
11209 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11210 { }
11211};
11212
Takashi Iwaia9111322011-05-02 11:30:18 +020011213static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011214 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11215 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011216 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11217 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011218 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11219 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11220 { } /* end */
11221};
11222
Takashi Iwaia9111322011-05-02 11:30:18 +020011223static const struct hda_verb alc262_hp_rp5700_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010011224 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11225 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11226 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11227 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11228 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11229 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11230 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11231 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11232 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11233 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11234 {}
11235};
11236
Takashi Iwaia9111322011-05-02 11:30:18 +020011237static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
Kailang Yang8c427222008-01-10 13:03:59 +010011238 .num_items = 1,
11239 .items = {
11240 { "Line", 0x1 },
11241 },
11242};
11243
Takashi Iwai42171c12009-05-08 14:11:43 +020011244/* bind hp and internal speaker mute (with plug check) as master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011245#define alc262_hippo_master_update alc262_hp_master_update
Takashi Iwai42171c12009-05-08 14:11:43 +020011246#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011247#define alc262_hippo_master_sw_put alc262_hp_master_sw_put
Takashi Iwai5b319542007-07-26 11:49:22 +020011248
Takashi Iwai42171c12009-05-08 14:11:43 +020011249#define ALC262_HIPPO_MASTER_SWITCH \
11250 { \
11251 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11252 .name = "Master Playback Switch", \
11253 .info = snd_ctl_boolean_mono_info, \
11254 .get = alc262_hippo_master_sw_get, \
11255 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011256 }, \
11257 { \
11258 .iface = NID_MAPPING, \
11259 .name = "Master Playback Switch", \
11260 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11261 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011262 }
11263
Takashi Iwaia9111322011-05-02 11:30:18 +020011264static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011265 ALC262_HIPPO_MASTER_SWITCH,
11266 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11267 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11268 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11269 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11270 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11271 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11272 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011273 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011274 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11275 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011276 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011277 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11278 { } /* end */
11279};
11280
Takashi Iwaia9111322011-05-02 11:30:18 +020011281static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011282 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11283 ALC262_HIPPO_MASTER_SWITCH,
11284 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11285 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11286 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11287 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11288 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11289 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011290 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011291 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11292 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011293 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011294 { } /* end */
11295};
11296
11297/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011298static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011299{
11300 struct alc_spec *spec = codec->spec;
11301
11302 spec->autocfg.hp_pins[0] = 0x15;
11303 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011304 spec->automute = 1;
11305 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011306}
11307
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011308static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011309{
11310 struct alc_spec *spec = codec->spec;
11311
11312 spec->autocfg.hp_pins[0] = 0x1b;
11313 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011314 spec->automute = 1;
11315 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011316}
11317
11318
Takashi Iwaia9111322011-05-02 11:30:18 +020011319static const struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011320 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011321 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011322 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11323 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11324 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11325 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11326 { } /* end */
11327};
11328
Takashi Iwaia9111322011-05-02 11:30:18 +020011329static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011330 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11331 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011332 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11333 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11334 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11335 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11336 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11337 { } /* end */
11338};
Kailang Yang272a5272007-05-14 11:00:38 +020011339
Takashi Iwaia9111322011-05-02 11:30:18 +020011340static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011341 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11342 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11343 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11344 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11345 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11346 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11347 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11348 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011349 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011350 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11351 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011352 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011353 { } /* end */
11354};
11355
Takashi Iwaia9111322011-05-02 11:30:18 +020011356static const struct hda_verb alc262_tyan_verbs[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011357 /* Headphone automute */
11358 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11359 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11360 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11361
11362 /* P11 AUX_IN, white 4-pin connector */
11363 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11364 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11365 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11366 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11367
11368 {}
11369};
11370
11371/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011372static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011373{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011374 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011375
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011376 spec->autocfg.hp_pins[0] = 0x1b;
11377 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +020011378 spec->automute = 1;
11379 spec->automute_mode = ALC_AUTOMUTE_AMP;
Tony Vroonba340e82009-02-02 19:01:30 +000011380}
11381
Tony Vroonba340e82009-02-02 19:01:30 +000011382
Kailang Yangdf694da2005-12-05 19:42:22 +010011383#define alc262_capture_mixer alc882_capture_mixer
11384#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11385
11386/*
11387 * generic initialization of ADC, input mixers and output mixers
11388 */
Takashi Iwaia9111322011-05-02 11:30:18 +020011389static const struct hda_verb alc262_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011390 /*
11391 * Unmute ADC0-2 and set the default input to mic-in
11392 */
11393 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11394 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11395 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11396 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11397 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11398 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11399
Takashi Iwaicb53c622007-08-10 17:21:45 +020011400 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011401 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011402 * Note: PASD motherboards uses the Line In 2 as the input for
11403 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011404 */
11405 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011406 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11407 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11408 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11409 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11410 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011411
11412 /*
11413 * Set up output mixers (0x0c - 0x0e)
11414 */
11415 /* set vol=0 to output mixers */
11416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11417 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11418 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11419 /* set up input amps for analog loopback */
11420 /* Amp Indices: DAC = 0, mixer = 1 */
11421 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11423 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11424 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11425 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11426 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11427
11428 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11429 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11430 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11431 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11432 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11433 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11434
11435 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11436 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11437 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11438 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11439 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011440
Kailang Yangdf694da2005-12-05 19:42:22 +010011441 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11442 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011443
Kailang Yangdf694da2005-12-05 19:42:22 +010011444 /* FIXME: use matrix-type input source selection */
11445 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11446 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11447 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11448 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11449 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11450 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11451 /* Input mixer2 */
11452 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11453 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11454 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11455 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11456 /* Input mixer3 */
11457 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11458 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11459 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011460 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011461
11462 { }
11463};
11464
Takashi Iwaia9111322011-05-02 11:30:18 +020011465static const struct hda_verb alc262_eapd_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011466 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11467 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11468 { }
11469};
11470
Takashi Iwaia9111322011-05-02 11:30:18 +020011471static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +020011472 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11473 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11474 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11475
11476 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11477 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11478 {}
11479};
11480
Takashi Iwaia9111322011-05-02 11:30:18 +020011481static const struct hda_verb alc262_sony_unsol_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020011482 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11483 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11484 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11485
11486 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11487 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011488 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011489};
11490
Takashi Iwaia9111322011-05-02 11:30:18 +020011491static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011492 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11493 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11494 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11495 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11496 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011497 { } /* end */
11498};
11499
Takashi Iwaia9111322011-05-02 11:30:18 +020011500static const struct hda_verb alc262_toshiba_s06_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011501 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11502 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11503 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11504 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11505 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11506 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11507 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11508 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11509 {}
11510};
11511
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011512static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011513{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011514 struct alc_spec *spec = codec->spec;
11515
11516 spec->autocfg.hp_pins[0] = 0x15;
11517 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011518 spec->ext_mic.pin = 0x18;
11519 spec->ext_mic.mux_idx = 0;
11520 spec->int_mic.pin = 0x12;
11521 spec->int_mic.mux_idx = 9;
11522 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020011523 spec->automute = 1;
11524 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011525}
11526
Takashi Iwai834be882006-03-01 14:16:17 +010011527/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011528 * nec model
11529 * 0x15 = headphone
11530 * 0x16 = internal speaker
11531 * 0x18 = external mic
11532 */
11533
Takashi Iwaia9111322011-05-02 11:30:18 +020011534static const struct snd_kcontrol_new alc262_nec_mixer[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011535 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11536 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11537
11538 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11539 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011540 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011541
11542 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11543 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11544 { } /* end */
11545};
11546
Takashi Iwaia9111322011-05-02 11:30:18 +020011547static const struct hda_verb alc262_nec_verbs[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011548 /* Unmute Speaker */
11549 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11550
11551 /* Headphone */
11552 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11553 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11554
11555 /* External mic to headphone */
11556 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11557 /* External mic to speaker */
11558 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11559 {}
11560};
11561
11562/*
Takashi Iwai834be882006-03-01 14:16:17 +010011563 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011564 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11565 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011566 */
11567
Takashi Iwai20f5e0b2011-06-10 09:31:54 +020011568#define ALC_HP_EVENT ALC880_HP_EVENT
Takashi Iwai834be882006-03-01 14:16:17 +010011569
Takashi Iwaia9111322011-05-02 11:30:18 +020011570static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
Takashi Iwai834be882006-03-01 14:16:17 +010011571 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11572 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011573 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11574 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011575 {}
11576};
11577
Takashi Iwaia9111322011-05-02 11:30:18 +020011578static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011579 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11580 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11581 {}
11582};
11583
Takashi Iwaia9111322011-05-02 11:30:18 +020011584static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
Daniel T Chene2595322009-12-19 18:19:02 -050011585 /* Front Mic pin: input vref at 50% */
11586 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11587 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11588 {}
11589};
11590
Takashi Iwaia9111322011-05-02 11:30:18 +020011591static const struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011592 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011593 .items = {
11594 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011595 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011596 { "CD", 0x4 },
11597 },
11598};
11599
Takashi Iwaia9111322011-05-02 11:30:18 +020011600static const struct hda_input_mux alc262_HP_capture_source = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011601 .num_items = 5,
11602 .items = {
11603 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011604 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011605 { "Line", 0x2 },
11606 { "CD", 0x4 },
11607 { "AUX IN", 0x6 },
11608 },
11609};
11610
Takashi Iwaia9111322011-05-02 11:30:18 +020011611static const struct hda_input_mux alc262_HP_D7000_capture_source = {
zhejiangaccbe492007-08-31 12:36:05 +020011612 .num_items = 4,
11613 .items = {
11614 { "Mic", 0x0 },
11615 { "Front Mic", 0x2 },
11616 { "Line", 0x1 },
11617 { "CD", 0x4 },
11618 },
11619};
11620
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011621static void alc262_fujitsu_setup(struct hda_codec *codec)
Takashi Iwai834be882006-03-01 14:16:17 +010011622{
11623 struct alc_spec *spec = codec->spec;
Takashi Iwai834be882006-03-01 14:16:17 +010011624
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011625 spec->autocfg.hp_pins[0] = 0x14;
11626 spec->autocfg.hp_pins[1] = 0x1b;
11627 spec->autocfg.speaker_pins[0] = 0x15;
11628 spec->automute = 1;
11629 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011630}
11631
Takashi Iwai834be882006-03-01 14:16:17 +010011632/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaia9111322011-05-02 11:30:18 +020011633static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011634 .ops = &snd_hda_bind_vol,
11635 .values = {
11636 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11637 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11638 0
11639 },
11640};
Takashi Iwai834be882006-03-01 14:16:17 +010011641
Takashi Iwaia9111322011-05-02 11:30:18 +020011642static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011643 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011644 {
11645 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11646 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011647 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
11648 .info = snd_ctl_boolean_mono_info,
11649 .get = alc262_hp_master_sw_get,
11650 .put = alc262_hp_master_sw_put,
Takashi Iwai834be882006-03-01 14:16:17 +010011651 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011652 {
11653 .iface = NID_MAPPING,
11654 .name = "Master Playback Switch",
11655 .private_value = 0x1b,
11656 },
Takashi Iwai834be882006-03-01 14:16:17 +010011657 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11658 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011659 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011660 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11661 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011662 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011663 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11664 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011665 { } /* end */
11666};
11667
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011668static void alc262_lenovo_3000_setup(struct hda_codec *codec)
Jiang zhe0e31daf2008-03-20 12:12:39 +010011669{
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011670 struct alc_spec *spec = codec->spec;
Jiang zhe0e31daf2008-03-20 12:12:39 +010011671
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011672 spec->autocfg.hp_pins[0] = 0x1b;
11673 spec->autocfg.speaker_pins[0] = 0x14;
11674 spec->autocfg.speaker_pins[1] = 0x16;
11675 spec->automute = 1;
11676 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhe0e31daf2008-03-20 12:12:39 +010011677}
11678
Takashi Iwaia9111322011-05-02 11:30:18 +020011679static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011680 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11681 {
11682 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11683 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011684 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
11685 .info = snd_ctl_boolean_mono_info,
11686 .get = alc262_hp_master_sw_get,
11687 .put = alc262_hp_master_sw_put,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011688 },
11689 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11690 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011691 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011692 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11693 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011694 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011695 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11696 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011697 { } /* end */
11698};
11699
Takashi Iwaia9111322011-05-02 11:30:18 +020011700static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011701 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011702 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011703 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11704 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011705 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011706 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11707 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011708 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011709 { } /* end */
11710};
11711
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011712/* additional init verbs for Benq laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020011713static const struct hda_verb alc262_EAPD_verbs[] = {
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011714 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11715 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11716 {}
11717};
11718
Takashi Iwaia9111322011-05-02 11:30:18 +020011719static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
Kailang Yang83c34212007-07-05 11:43:05 +020011720 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11721 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11722
11723 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11724 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11725 {}
11726};
11727
Tobin Davisf651b502007-10-26 12:40:47 +020011728/* Samsung Q1 Ultra Vista model setup */
Takashi Iwaia9111322011-05-02 11:30:18 +020011729static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011730 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11731 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011732 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11733 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011734 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
11735 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011736 { } /* end */
11737};
11738
Takashi Iwaia9111322011-05-02 11:30:18 +020011739static const struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011740 /* output mixer */
11741 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11742 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11743 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11744 /* speaker */
11745 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11746 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11747 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11748 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11749 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011750 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011751 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11752 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11753 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11754 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11755 /* internal mic */
11756 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11757 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11758 /* ADC, choose mic */
11759 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11760 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11761 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11762 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11763 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11764 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11765 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11766 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11767 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11768 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011769 {}
11770};
11771
Tobin Davisf651b502007-10-26 12:40:47 +020011772/* mute/unmute internal speaker according to the hp jack and mute state */
11773static void alc262_ultra_automute(struct hda_codec *codec)
11774{
11775 struct alc_spec *spec = codec->spec;
11776 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011777
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011778 mute = 0;
11779 /* auto-mute only when HP is used as HP */
11780 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011781 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011782 if (spec->jack_present)
11783 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011784 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011785 /* mute/unmute internal speaker */
11786 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11787 HDA_AMP_MUTE, mute);
11788 /* mute/unmute HP */
11789 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11790 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011791}
11792
11793/* unsolicited event for HP jack sensing */
11794static void alc262_ultra_unsol_event(struct hda_codec *codec,
11795 unsigned int res)
11796{
11797 if ((res >> 26) != ALC880_HP_EVENT)
11798 return;
11799 alc262_ultra_automute(codec);
11800}
11801
Takashi Iwaia9111322011-05-02 11:30:18 +020011802static const struct hda_input_mux alc262_ultra_capture_source = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011803 .num_items = 2,
11804 .items = {
11805 { "Mic", 0x1 },
11806 { "Headphone", 0x7 },
11807 },
11808};
11809
11810static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11811 struct snd_ctl_elem_value *ucontrol)
11812{
11813 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11814 struct alc_spec *spec = codec->spec;
11815 int ret;
11816
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011817 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011818 if (!ret)
11819 return 0;
11820 /* reprogram the HP pin as mic or HP according to the input source */
11821 snd_hda_codec_write_cache(codec, 0x15, 0,
11822 AC_VERB_SET_PIN_WIDGET_CONTROL,
11823 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11824 alc262_ultra_automute(codec); /* mute/unmute HP */
11825 return ret;
11826}
11827
Takashi Iwaia9111322011-05-02 11:30:18 +020011828static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011829 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11830 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11831 {
11832 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11833 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011834 .info = alc_mux_enum_info,
11835 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011836 .put = alc262_ultra_mux_enum_put,
11837 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011838 {
11839 .iface = NID_MAPPING,
11840 .name = "Capture Source",
11841 .private_value = 0x15,
11842 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011843 { } /* end */
11844};
11845
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011846/* We use two mixers depending on the output pin; 0x16 is a mono output
11847 * and thus it's bound with a different mixer.
11848 * This function returns which mixer amp should be used.
11849 */
11850static int alc262_check_volbit(hda_nid_t nid)
11851{
11852 if (!nid)
11853 return 0;
11854 else if (nid == 0x16)
11855 return 2;
11856 else
11857 return 1;
11858}
11859
11860static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011861 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011862{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011863 unsigned long val;
11864 int vbit;
11865
11866 vbit = alc262_check_volbit(nid);
11867 if (!vbit)
11868 return 0;
11869 if (*vbits & vbit) /* a volume control for this mixer already there */
11870 return 0;
11871 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011872 if (vbit == 2)
11873 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11874 else
11875 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011876 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011877}
11878
11879static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011880 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011881{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011882 unsigned long val;
11883
11884 if (!nid)
11885 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011886 if (nid == 0x16)
11887 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11888 else
11889 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011890 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011891}
11892
Kailang Yangdf694da2005-12-05 19:42:22 +010011893/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011894static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11895 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011896{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011897 const char *pfx;
11898 int vbits;
Takashi Iwai6843ca12011-06-24 11:03:58 +020011899 int i, index, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011900
11901 spec->multiout.num_dacs = 1; /* only use one dac */
11902 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +020011903 spec->private_dac_nids[0] = 2;
Kailang Yangdf694da2005-12-05 19:42:22 +010011904
Takashi Iwai033688a2010-09-08 15:47:09 +020011905 for (i = 0; i < 2; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020011906 pfx = alc_get_line_out_pfx(spec, i, true, &index);
11907 if (!pfx)
11908 pfx = "PCM";
11909 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx,
11910 index);
Takashi Iwai033688a2010-09-08 15:47:09 +020011911 if (err < 0)
11912 return err;
11913 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
11914 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
11915 "Speaker", i);
11916 if (err < 0)
11917 return err;
11918 }
11919 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
11920 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
11921 "Headphone", i);
11922 if (err < 0)
11923 return err;
11924 }
11925 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011926
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011927 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11928 alc262_check_volbit(cfg->speaker_pins[0]) |
11929 alc262_check_volbit(cfg->hp_pins[0]);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011930 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020011931 for (i = 0; i < 2; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020011932 pfx = alc_get_line_out_pfx(spec, i, true, &index);
11933 if (!pfx)
11934 pfx = "PCM";
Takashi Iwai033688a2010-09-08 15:47:09 +020011935 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
11936 &vbits, i);
11937 if (err < 0)
11938 return err;
11939 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
11940 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
11941 "Speaker", &vbits, i);
11942 if (err < 0)
11943 return err;
11944 }
11945 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
11946 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
11947 "Headphone", &vbits, i);
11948 if (err < 0)
11949 return err;
11950 }
11951 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011952 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011953}
11954
Takashi Iwaia9111322011-05-02 11:30:18 +020011955static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011956 /*
11957 * Unmute ADC0-2 and set the default input to mic-in
11958 */
11959 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11960 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11961 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11962 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11963 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11964 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11965
Takashi Iwaicb53c622007-08-10 17:21:45 +020011966 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011967 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011968 * Note: PASD motherboards uses the Line In 2 as the input for
11969 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011970 */
11971 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011972 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11973 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11974 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11975 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11976 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11977 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11978 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011979
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011980 /*
11981 * Set up output mixers (0x0c - 0x0e)
11982 */
11983 /* set vol=0 to output mixers */
11984 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11985 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11986 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11987
11988 /* set up input amps for analog loopback */
11989 /* Amp Indices: DAC = 0, mixer = 1 */
11990 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11991 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11992 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11993 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11994 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11995 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11996
Takashi Iwaice875f02008-01-28 18:17:43 +010011997 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011998 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
11999 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12000
12001 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12002 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12003
12004 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12005 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12006
12007 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12008 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12009 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12010 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12011 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12012
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012013 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012014 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12015 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012016 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012017 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12018 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12019
12020
12021 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012022 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12023 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012024 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012025 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12026 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12027 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12028 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12029 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12030 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12031 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12032 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012033 /* Input mixer2 */
12034 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012035 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12036 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12037 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12038 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12039 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12040 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12041 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12042 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012043 /* Input mixer3 */
12044 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012045 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12046 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12047 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12048 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12049 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12050 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12051 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12052 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012053
Takashi Iwaice875f02008-01-28 18:17:43 +010012054 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12055
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012056 { }
12057};
12058
Takashi Iwaia9111322011-05-02 11:30:18 +020012059static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010012060 /*
12061 * Unmute ADC0-2 and set the default input to mic-in
12062 */
12063 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12064 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12065 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12066 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12067 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12068 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12069
Takashi Iwaicb53c622007-08-10 17:21:45 +020012070 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012071 * mixer widget
12072 * Note: PASD motherboards uses the Line In 2 as the input for front
12073 * panel mic (mic 2)
12074 */
12075 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012076 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12077 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12078 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12079 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12080 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12081 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12082 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12083 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012084 /*
12085 * Set up output mixers (0x0c - 0x0e)
12086 */
12087 /* set vol=0 to output mixers */
12088 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12089 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12090 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12091
12092 /* set up input amps for analog loopback */
12093 /* Amp Indices: DAC = 0, mixer = 1 */
12094 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12095 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12096 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12097 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12098 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12099 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12100
12101
12102 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12103 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12104 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12105 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12106 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12107 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12108 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12109
12110 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12111 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12112
12113 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12114 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12115
12116 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12117 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12118 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12119 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12120 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12121 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12122
12123 /* FIXME: use matrix-type input source selection */
12124 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12125 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12126 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12127 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12128 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12129 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12130 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12131 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12132 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12133 /* Input mixer2 */
12134 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12135 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12136 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12137 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12138 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12139 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12140 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12141 /* Input mixer3 */
12142 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12143 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12144 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12145 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12146 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12147 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12148 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12149
Takashi Iwaice875f02008-01-28 18:17:43 +010012150 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12151
Kailang Yangcd7509a2007-01-26 18:33:17 +010012152 { }
12153};
12154
Takashi Iwaia9111322011-05-02 11:30:18 +020012155static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012156
12157 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12158 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12159 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12160
12161 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12162 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12163 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12164 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12165
12166 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12167 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12168 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12169 {}
12170};
12171
Takashi Iwai18675e42010-09-08 15:55:44 +020012172/*
12173 * Pin config fixes
12174 */
12175enum {
12176 PINFIX_FSC_H270,
David Henningssond2a19da2011-06-22 09:58:37 +020012177 PINFIX_HP_Z200,
Takashi Iwai18675e42010-09-08 15:55:44 +020012178};
12179
12180static const struct alc_fixup alc262_fixups[] = {
12181 [PINFIX_FSC_H270] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012182 .type = ALC_FIXUP_PINS,
12183 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai18675e42010-09-08 15:55:44 +020012184 { 0x14, 0x99130110 }, /* speaker */
12185 { 0x15, 0x0221142f }, /* front HP */
12186 { 0x1b, 0x0121141f }, /* rear HP */
12187 { }
12188 }
12189 },
David Henningssond2a19da2011-06-22 09:58:37 +020012190 [PINFIX_HP_Z200] = {
12191 .type = ALC_FIXUP_PINS,
12192 .v.pins = (const struct alc_pincfg[]) {
12193 { 0x16, 0x99130120 }, /* internal speaker */
12194 { }
12195 }
12196 },
Takashi Iwai18675e42010-09-08 15:55:44 +020012197};
12198
Takashi Iwaia9111322011-05-02 11:30:18 +020012199static const struct snd_pci_quirk alc262_fixup_tbl[] = {
David Henningssond2a19da2011-06-22 09:58:37 +020012200 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
Takashi Iwai18675e42010-09-08 15:55:44 +020012201 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12202 {}
12203};
12204
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012205
Takashi Iwaicb53c622007-08-10 17:21:45 +020012206#ifdef CONFIG_SND_HDA_POWER_SAVE
12207#define alc262_loopbacks alc880_loopbacks
12208#endif
12209
Kailang Yangdf694da2005-12-05 19:42:22 +010012210/*
12211 * BIOS auto configuration
12212 */
12213static int alc262_parse_auto_config(struct hda_codec *codec)
12214{
12215 struct alc_spec *spec = codec->spec;
12216 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012217 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012218
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012219 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12220 alc262_ignore);
12221 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012222 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012223 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012224 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012225 spec->multiout.max_channels = 2;
12226 spec->no_analog = 1;
12227 goto dig_only;
12228 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012229 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012230 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012231 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12232 if (err < 0)
12233 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020012234 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012235 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012236 return err;
12237
12238 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12239
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012240 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012241 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012242
Takashi Iwai603c4012008-07-30 15:01:44 +020012243 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012244 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012245
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012246 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012247 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012248
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020012249 if (!spec->dual_adc_switch)
12250 alc_remove_invalid_adc_nids(codec);
12251
Takashi Iwai776e1842007-08-29 15:07:11 +020012252 err = alc_auto_add_mic_boost(codec);
12253 if (err < 0)
12254 return err;
12255
Kailang Yang6227cdc2010-02-25 08:36:52 +010012256 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012257
Kailang Yangdf694da2005-12-05 19:42:22 +010012258 return 1;
12259}
12260
Kailang Yangdf694da2005-12-05 19:42:22 +010012261
12262/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012263static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012264{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012265 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020012266 alc_auto_init_multi_out(codec);
12267 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020012268 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020012269 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012270 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012271 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012272 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012273}
12274
12275/*
12276 * configuration and preset
12277 */
Takashi Iwaiea734962011-01-17 11:29:34 +010012278static const char * const alc262_models[ALC262_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012279 [ALC262_BASIC] = "basic",
12280 [ALC262_HIPPO] = "hippo",
12281 [ALC262_HIPPO_1] = "hippo_1",
12282 [ALC262_FUJITSU] = "fujitsu",
12283 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012284 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012285 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012286 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012287 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012288 [ALC262_BENQ_T31] = "benq-t31",
12289 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012290 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012291 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012292 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012293 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012294 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012295 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012296 [ALC262_AUTO] = "auto",
12297};
12298
Takashi Iwaia9111322011-05-02 11:30:18 +020012299static const struct snd_pci_quirk alc262_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012300 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012301 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012302 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12303 ALC262_HP_BPC),
12304 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12305 ALC262_HP_BPC),
Takashi Iwai5734a072011-01-19 17:07:12 +010012306 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
12307 ALC262_HP_BPC),
David Henningssond2a19da2011-06-22 09:58:37 +020012308 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
12309 ALC262_AUTO),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012310 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12311 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012312 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012313 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012314 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012315 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012316 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012317 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012318 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012319 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012320 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12321 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12322 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012323 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12324 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012325 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012326 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012327 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012328 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012329 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012330 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012331 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012332 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012333#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012334 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12335 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012336#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012337 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012338 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012339 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012340 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012341 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012342 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012343 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12344 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012345 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012346 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012347 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012348 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012349 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012350 {}
12351};
12352
Takashi Iwaia9111322011-05-02 11:30:18 +020012353static const struct alc_config_preset alc262_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010012354 [ALC262_BASIC] = {
12355 .mixers = { alc262_base_mixer },
12356 .init_verbs = { alc262_init_verbs },
12357 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12358 .dac_nids = alc262_dac_nids,
12359 .hp_nid = 0x03,
12360 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12361 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012362 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012363 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012364 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012365 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012366 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012367 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12368 .dac_nids = alc262_dac_nids,
12369 .hp_nid = 0x03,
12370 .dig_out_nid = ALC262_DIGOUT_NID,
12371 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12372 .channel_mode = alc262_modes,
12373 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012374 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012375 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012376 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012377 },
12378 [ALC262_HIPPO_1] = {
12379 .mixers = { alc262_hippo1_mixer },
12380 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12381 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12382 .dac_nids = alc262_dac_nids,
12383 .hp_nid = 0x02,
12384 .dig_out_nid = ALC262_DIGOUT_NID,
12385 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12386 .channel_mode = alc262_modes,
12387 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012388 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012389 .setup = alc262_hippo1_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012390 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012391 },
Takashi Iwai834be882006-03-01 14:16:17 +010012392 [ALC262_FUJITSU] = {
12393 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012394 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12395 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012396 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12397 .dac_nids = alc262_dac_nids,
12398 .hp_nid = 0x03,
12399 .dig_out_nid = ALC262_DIGOUT_NID,
12400 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12401 .channel_mode = alc262_modes,
12402 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012403 .unsol_event = alc_sku_unsol_event,
12404 .setup = alc262_fujitsu_setup,
12405 .init_hook = alc_inithook,
Takashi Iwai834be882006-03-01 14:16:17 +010012406 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012407 [ALC262_HP_BPC] = {
12408 .mixers = { alc262_HP_BPC_mixer },
12409 .init_verbs = { alc262_HP_BPC_init_verbs },
12410 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12411 .dac_nids = alc262_dac_nids,
12412 .hp_nid = 0x03,
12413 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12414 .channel_mode = alc262_modes,
12415 .input_mux = &alc262_HP_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012416 .unsol_event = alc_sku_unsol_event,
12417 .setup = alc262_hp_bpc_setup,
12418 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012419 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012420 [ALC262_HP_BPC_D7000_WF] = {
12421 .mixers = { alc262_HP_BPC_WildWest_mixer },
12422 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12423 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12424 .dac_nids = alc262_dac_nids,
12425 .hp_nid = 0x03,
12426 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12427 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012428 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012429 .unsol_event = alc_sku_unsol_event,
12430 .setup = alc262_hp_wildwest_setup,
12431 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012432 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012433 [ALC262_HP_BPC_D7000_WL] = {
12434 .mixers = { alc262_HP_BPC_WildWest_mixer,
12435 alc262_HP_BPC_WildWest_option_mixer },
12436 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12437 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12438 .dac_nids = alc262_dac_nids,
12439 .hp_nid = 0x03,
12440 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12441 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012442 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012443 .unsol_event = alc_sku_unsol_event,
12444 .setup = alc262_hp_wildwest_setup,
12445 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012446 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012447 [ALC262_HP_TC_T5735] = {
12448 .mixers = { alc262_hp_t5735_mixer },
12449 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12450 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12451 .dac_nids = alc262_dac_nids,
12452 .hp_nid = 0x03,
12453 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12454 .channel_mode = alc262_modes,
12455 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012456 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012457 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012458 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012459 },
12460 [ALC262_HP_RP5700] = {
12461 .mixers = { alc262_hp_rp5700_mixer },
12462 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12463 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12464 .dac_nids = alc262_dac_nids,
12465 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12466 .channel_mode = alc262_modes,
12467 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012468 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012469 [ALC262_BENQ_ED8] = {
12470 .mixers = { alc262_base_mixer },
12471 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12472 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12473 .dac_nids = alc262_dac_nids,
12474 .hp_nid = 0x03,
12475 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12476 .channel_mode = alc262_modes,
12477 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012478 },
Kailang Yang272a5272007-05-14 11:00:38 +020012479 [ALC262_SONY_ASSAMD] = {
12480 .mixers = { alc262_sony_mixer },
12481 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12482 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12483 .dac_nids = alc262_dac_nids,
12484 .hp_nid = 0x02,
12485 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12486 .channel_mode = alc262_modes,
12487 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012488 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012489 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012490 .init_hook = alc_inithook,
Kailang Yang83c34212007-07-05 11:43:05 +020012491 },
12492 [ALC262_BENQ_T31] = {
12493 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012494 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12495 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012496 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12497 .dac_nids = alc262_dac_nids,
12498 .hp_nid = 0x03,
12499 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12500 .channel_mode = alc262_modes,
12501 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012502 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012503 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012504 .init_hook = alc_inithook,
Kailang Yangea1fb292008-08-26 12:58:38 +020012505 },
Tobin Davisf651b502007-10-26 12:40:47 +020012506 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012507 .mixers = { alc262_ultra_mixer },
12508 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012509 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012510 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12511 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012512 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12513 .channel_mode = alc262_modes,
12514 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012515 .adc_nids = alc262_adc_nids, /* ADC0 */
12516 .capsrc_nids = alc262_capsrc_nids,
12517 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012518 .unsol_event = alc262_ultra_unsol_event,
12519 .init_hook = alc262_ultra_automute,
12520 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012521 [ALC262_LENOVO_3000] = {
12522 .mixers = { alc262_lenovo_3000_mixer },
12523 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012524 alc262_lenovo_3000_unsol_verbs,
12525 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012526 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12527 .dac_nids = alc262_dac_nids,
12528 .hp_nid = 0x03,
12529 .dig_out_nid = ALC262_DIGOUT_NID,
12530 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12531 .channel_mode = alc262_modes,
12532 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012533 .unsol_event = alc_sku_unsol_event,
12534 .setup = alc262_lenovo_3000_setup,
12535 .init_hook = alc_inithook,
Jiang zhe0e31daf2008-03-20 12:12:39 +010012536 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012537 [ALC262_NEC] = {
12538 .mixers = { alc262_nec_mixer },
12539 .init_verbs = { alc262_nec_verbs },
12540 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12541 .dac_nids = alc262_dac_nids,
12542 .hp_nid = 0x03,
12543 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12544 .channel_mode = alc262_modes,
12545 .input_mux = &alc262_capture_source,
12546 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012547 [ALC262_TOSHIBA_S06] = {
12548 .mixers = { alc262_toshiba_s06_mixer },
12549 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12550 alc262_eapd_verbs },
12551 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12552 .capsrc_nids = alc262_dmic_capsrc_nids,
12553 .dac_nids = alc262_dac_nids,
12554 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012555 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012556 .dig_out_nid = ALC262_DIGOUT_NID,
12557 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12558 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012559 .unsol_event = alc_sku_unsol_event,
12560 .setup = alc262_toshiba_s06_setup,
12561 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012562 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012563 [ALC262_TOSHIBA_RX1] = {
12564 .mixers = { alc262_toshiba_rx1_mixer },
12565 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12566 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12567 .dac_nids = alc262_dac_nids,
12568 .hp_nid = 0x03,
12569 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12570 .channel_mode = alc262_modes,
12571 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012572 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012573 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012574 .init_hook = alc_inithook,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012575 },
Tony Vroonba340e82009-02-02 19:01:30 +000012576 [ALC262_TYAN] = {
12577 .mixers = { alc262_tyan_mixer },
12578 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12579 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12580 .dac_nids = alc262_dac_nids,
12581 .hp_nid = 0x02,
12582 .dig_out_nid = ALC262_DIGOUT_NID,
12583 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12584 .channel_mode = alc262_modes,
12585 .input_mux = &alc262_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020012586 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012587 .setup = alc262_tyan_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020012588 .init_hook = alc_hp_automute,
Tony Vroonba340e82009-02-02 19:01:30 +000012589 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012590};
12591
12592static int patch_alc262(struct hda_codec *codec)
12593{
12594 struct alc_spec *spec;
12595 int board_config;
12596 int err;
12597
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012598 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012599 if (spec == NULL)
12600 return -ENOMEM;
12601
12602 codec->spec = spec;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020012603
12604 spec->mixer_nid = 0x0b;
12605
Kailang Yangdf694da2005-12-05 19:42:22 +010012606#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012607 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12608 * under-run
12609 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012610 {
12611 int tmp;
12612 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12613 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12614 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12615 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12616 }
12617#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012618 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012619
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012620 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12621
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012622 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12623 alc262_models,
12624 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012625
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012626 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012627 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12628 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012629 board_config = ALC262_AUTO;
12630 }
12631
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012632 if (board_config == ALC262_AUTO) {
12633 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
12634 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
12635 }
Takashi Iwai18675e42010-09-08 15:55:44 +020012636
Kailang Yangdf694da2005-12-05 19:42:22 +010012637 if (board_config == ALC262_AUTO) {
12638 /* automatic parse from the BIOS config */
12639 err = alc262_parse_auto_config(codec);
12640 if (err < 0) {
12641 alc_free(codec);
12642 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012643 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012644 printk(KERN_INFO
12645 "hda_codec: Cannot set up configuration "
12646 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012647 board_config = ALC262_BASIC;
12648 }
12649 }
12650
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012651 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012652 err = snd_hda_attach_beep_device(codec, 0x1);
12653 if (err < 0) {
12654 alc_free(codec);
12655 return err;
12656 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012657 }
12658
Kailang Yangdf694da2005-12-05 19:42:22 +010012659 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012660 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012661
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012662 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020012663 alc_auto_fill_adc_caps(codec);
12664 alc_remove_invalid_adc_nids(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012665 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012666 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012667 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012668 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012669 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012670
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012671 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai18675e42010-09-08 15:55:44 +020012672
Takashi Iwai2134ea42008-01-10 16:53:55 +010012673 spec->vmaster_nid = 0x0c;
12674
Kailang Yangdf694da2005-12-05 19:42:22 +010012675 codec->patch_ops = alc_patch_ops;
12676 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012677 spec->init_hook = alc262_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020012678 spec->shutup = alc_eapd_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020012679
12680 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020012681#ifdef CONFIG_SND_HDA_POWER_SAVE
12682 if (!spec->loopback.amplist)
12683 spec->loopback.amplist = alc262_loopbacks;
12684#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012685
Kailang Yangdf694da2005-12-05 19:42:22 +010012686 return 0;
12687}
12688
Kailang Yangdf694da2005-12-05 19:42:22 +010012689/*
Kailang Yanga361d842007-06-05 12:30:55 +020012690 * ALC268 channel source setting (2 channel)
12691 */
12692#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12693#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012694
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012695static const hda_nid_t alc268_dac_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012696 /* front, hp */
12697 0x02, 0x03
12698};
12699
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012700static const hda_nid_t alc268_adc_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012701 /* ADC0-1 */
12702 0x08, 0x07
12703};
12704
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012705static const hda_nid_t alc268_adc_nids_alt[1] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012706 /* ADC0 */
12707 0x08
12708};
12709
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012710static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
Takashi Iwaie1406342008-02-11 18:32:32 +010012711
Takashi Iwaia9111322011-05-02 11:30:18 +020012712static const struct snd_kcontrol_new alc268_base_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012713 /* output mixer control */
12714 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12715 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12716 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12717 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012718 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12719 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
12720 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012721 { }
12722};
12723
Takashi Iwaia9111322011-05-02 11:30:18 +020012724static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012725 /* output mixer control */
12726 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12727 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12728 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010012729 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12730 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
12731 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020012732 { }
12733};
12734
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012735/* bind Beep switches of both NID 0x0f and 0x10 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012736static const struct hda_bind_ctls alc268_bind_beep_sw = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012737 .ops = &snd_hda_bind_sw,
12738 .values = {
12739 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12740 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12741 0
12742 },
12743};
12744
Takashi Iwaia9111322011-05-02 11:30:18 +020012745static const struct snd_kcontrol_new alc268_beep_mixer[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012746 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12747 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12748 { }
12749};
12750
Takashi Iwaia9111322011-05-02 11:30:18 +020012751static const struct hda_verb alc268_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020012752 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12753 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12754 { }
12755};
12756
Takashi Iwaid2738092007-08-16 14:59:45 +020012757/* Toshiba specific */
Takashi Iwaia9111322011-05-02 11:30:18 +020012758static const struct hda_verb alc268_toshiba_verbs[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020012759 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12760 { } /* end */
12761};
12762
12763/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012764/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012765static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
Takashi Iwai6bc96852007-08-17 09:02:12 +020012766 .ops = &snd_hda_bind_vol,
12767 .values = {
12768 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12769 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12770 0
12771 },
12772};
12773
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012774static void alc268_acer_setup(struct hda_codec *codec)
Takashi Iwai889c4392007-08-23 18:56:52 +020012775{
12776 struct alc_spec *spec = codec->spec;
Takashi Iwai889c4392007-08-23 18:56:52 +020012777
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012778 spec->autocfg.hp_pins[0] = 0x14;
12779 spec->autocfg.speaker_pins[0] = 0x15;
12780 spec->automute = 1;
12781 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai889c4392007-08-23 18:56:52 +020012782}
12783
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012784#define alc268_acer_master_sw_get alc262_hp_master_sw_get
12785#define alc268_acer_master_sw_put alc262_hp_master_sw_put
Takashi Iwaid2738092007-08-16 14:59:45 +020012786
Takashi Iwaia9111322011-05-02 11:30:18 +020012787static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020012788 /* output mixer control */
12789 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12790 {
12791 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12792 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012793 .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
12794 .info = snd_ctl_boolean_mono_info,
12795 .get = alc268_acer_master_sw_get,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012796 .put = alc268_acer_master_sw_put,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012797 },
12798 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12799 { }
12800};
12801
Takashi Iwaia9111322011-05-02 11:30:18 +020012802static const struct snd_kcontrol_new alc268_acer_mixer[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020012803 /* output mixer control */
12804 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12805 {
12806 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12807 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012808 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12809 .info = snd_ctl_boolean_mono_info,
12810 .get = alc268_acer_master_sw_get,
Takashi Iwaid2738092007-08-16 14:59:45 +020012811 .put = alc268_acer_master_sw_put,
Takashi Iwaid2738092007-08-16 14:59:45 +020012812 },
David Henningsson5f99f862011-01-04 15:24:24 +010012813 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12814 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
12815 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012816 { }
12817};
12818
Takashi Iwaia9111322011-05-02 11:30:18 +020012819static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012820 /* output mixer control */
12821 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12822 {
12823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12824 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012825 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12826 .info = snd_ctl_boolean_mono_info,
12827 .get = alc268_acer_master_sw_get,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012828 .put = alc268_acer_master_sw_put,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012829 },
David Henningsson5f99f862011-01-04 15:24:24 +010012830 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12831 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012832 { }
12833};
12834
Takashi Iwaia9111322011-05-02 11:30:18 +020012835static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020012836 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12837 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12838 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12839 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12840 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12841 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12842 { }
12843};
12844
Takashi Iwaia9111322011-05-02 11:30:18 +020012845static const struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012846 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12847 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012848 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12849 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012850 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12851 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012852 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12853 { }
12854};
12855
12856/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012857#define alc268_toshiba_setup alc262_hippo_setup
Takashi Iwaid2738092007-08-16 14:59:45 +020012858
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012859static void alc268_acer_lc_setup(struct hda_codec *codec)
12860{
12861 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020012862 spec->autocfg.hp_pins[0] = 0x15;
12863 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020012864 spec->automute = 1;
Takashi Iwai54463a62011-06-13 08:32:06 +020012865 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012866 spec->ext_mic.pin = 0x18;
12867 spec->ext_mic.mux_idx = 0;
12868 spec->int_mic.pin = 0x12;
12869 spec->int_mic.mux_idx = 6;
12870 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012871}
12872
Takashi Iwaia9111322011-05-02 11:30:18 +020012873static const struct snd_kcontrol_new alc268_dell_mixer[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012874 /* output mixer control */
12875 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12876 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12877 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12878 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012879 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12880 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012881 { }
12882};
12883
Takashi Iwaia9111322011-05-02 11:30:18 +020012884static const struct hda_verb alc268_dell_verbs[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012885 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12886 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12887 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012888 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012889 { }
12890};
12891
12892/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012893static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012894{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012895 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012896
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012897 spec->autocfg.hp_pins[0] = 0x15;
12898 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012899 spec->ext_mic.pin = 0x18;
12900 spec->ext_mic.mux_idx = 0;
12901 spec->int_mic.pin = 0x19;
12902 spec->int_mic.mux_idx = 1;
12903 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020012904 spec->automute = 1;
12905 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012906}
12907
Takashi Iwaia9111322011-05-02 11:30:18 +020012908static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012909 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12910 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12911 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12912 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12913 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12914 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012915 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12916 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012917 { }
12918};
12919
Takashi Iwaia9111322011-05-02 11:30:18 +020012920static const struct hda_verb alc267_quanta_il1_verbs[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012921 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12922 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12923 { }
12924};
12925
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012926static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012927{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012928 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012929 spec->autocfg.hp_pins[0] = 0x15;
12930 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012931 spec->ext_mic.pin = 0x18;
12932 spec->ext_mic.mux_idx = 0;
12933 spec->int_mic.pin = 0x19;
12934 spec->int_mic.mux_idx = 1;
12935 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020012936 spec->automute = 1;
12937 spec->automute_mode = ALC_AUTOMUTE_PIN;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012938}
12939
Kailang Yanga361d842007-06-05 12:30:55 +020012940/*
12941 * generic initialization of ADC, input mixers and output mixers
12942 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012943static const struct hda_verb alc268_base_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012944 /* Unmute DAC0-1 and set vol = 0 */
12945 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012946 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012947
12948 /*
12949 * Set up output mixers (0x0c - 0x0e)
12950 */
12951 /* set vol=0 to output mixers */
12952 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012953 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12954
12955 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12956 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12957
12958 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12959 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12960 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12961 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12962 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12963 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12964 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12965 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12966
12967 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12968 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12969 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12970 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012971 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012972
12973 /* set PCBEEP vol = 0, mute connections */
12974 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12975 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12976 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012977
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012978 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020012979
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012980 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
12981 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12982 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
12983 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012984
Kailang Yanga361d842007-06-05 12:30:55 +020012985 { }
12986};
12987
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020012988/* only for model=test */
12989#ifdef CONFIG_SND_DEBUG
Kailang Yanga361d842007-06-05 12:30:55 +020012990/*
12991 * generic initialization of ADC, input mixers and output mixers
12992 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012993static const struct hda_verb alc268_volume_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012994 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010012995 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12996 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012997
12998 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12999 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13000 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13001 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13002 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13003
Kailang Yanga361d842007-06-05 12:30:55 +020013004 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013005 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13006 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13007
13008 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013009 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013010 { }
13011};
13012#endif /* CONFIG_SND_DEBUG */
Kailang Yanga361d842007-06-05 12:30:55 +020013013
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013014/* set PCBEEP vol = 0, mute connections */
13015static const struct hda_verb alc268_beep_init_verbs[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013016 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13017 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13018 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013019 { }
13020};
13021
Takashi Iwaia9111322011-05-02 11:30:18 +020013022static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013023 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13024 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13025 { } /* end */
13026};
13027
Takashi Iwaia9111322011-05-02 11:30:18 +020013028static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013029 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13030 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013031 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013032 { } /* end */
13033};
13034
Takashi Iwaia9111322011-05-02 11:30:18 +020013035static const struct snd_kcontrol_new alc268_capture_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013036 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13037 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13038 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13039 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013040 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013041 { } /* end */
13042};
13043
Takashi Iwaia9111322011-05-02 11:30:18 +020013044static const struct hda_input_mux alc268_capture_source = {
Kailang Yanga361d842007-06-05 12:30:55 +020013045 .num_items = 4,
13046 .items = {
13047 { "Mic", 0x0 },
13048 { "Front Mic", 0x1 },
13049 { "Line", 0x2 },
13050 { "CD", 0x3 },
13051 },
13052};
13053
Takashi Iwaia9111322011-05-02 11:30:18 +020013054static const struct hda_input_mux alc268_acer_capture_source = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013055 .num_items = 3,
13056 .items = {
13057 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013058 { "Internal Mic", 0x1 },
13059 { "Line", 0x2 },
13060 },
13061};
13062
Takashi Iwaia9111322011-05-02 11:30:18 +020013063static const struct hda_input_mux alc268_acer_dmic_capture_source = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013064 .num_items = 3,
13065 .items = {
13066 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013067 { "Internal Mic", 0x6 },
13068 { "Line", 0x2 },
13069 },
13070};
13071
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013072#ifdef CONFIG_SND_DEBUG
Takashi Iwaia9111322011-05-02 11:30:18 +020013073static const struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013074 /* Volume widgets */
13075 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13076 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13077 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13078 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13079 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13080 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13081 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13082 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13083 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13084 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13085 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13086 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13087 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013088 /* The below appears problematic on some hardwares */
13089 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013090 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13091 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13092 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13093 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13094
13095 /* Modes for retasking pin widgets */
13096 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13097 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13098 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13099 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13100
13101 /* Controls for GPIO pins, assuming they are configured as outputs */
13102 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13103 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13104 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13105 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13106
13107 /* Switches to allow the digital SPDIF output pin to be enabled.
13108 * The ALC268 does not have an SPDIF input.
13109 */
13110 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13111
13112 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13113 * this output to turn on an external amplifier.
13114 */
13115 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13116 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13117
13118 { } /* end */
13119};
13120#endif
13121
Kailang Yanga361d842007-06-05 12:30:55 +020013122/* create input playback/capture controls for the given pin */
13123static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13124 const char *ctlname, int idx)
13125{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013126 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013127 int err;
13128
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013129 switch (nid) {
13130 case 0x14:
13131 case 0x16:
13132 dac = 0x02;
13133 break;
13134 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013135 case 0x1a: /* ALC259/269 only */
13136 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013137 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013138 dac = 0x03;
13139 break;
13140 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013141 snd_printd(KERN_WARNING "hda_codec: "
13142 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013143 return 0;
13144 }
13145 if (spec->multiout.dac_nids[0] != dac &&
13146 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013147 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013148 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013149 HDA_OUTPUT));
13150 if (err < 0)
13151 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020013152 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013153 }
13154
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013155 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013156 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013157 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013158 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013159 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013160 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013161 if (err < 0)
13162 return err;
13163 return 0;
13164}
13165
13166/* add playback controls from the parsed DAC table */
13167static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13168 const struct auto_pin_cfg *cfg)
13169{
13170 hda_nid_t nid;
13171 int err;
13172
Kailang Yanga361d842007-06-05 12:30:55 +020013173 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013174
13175 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013176 if (nid) {
13177 const char *name;
Takashi Iwai2e925dd2011-06-24 11:27:22 +020013178 int index;
13179 name = alc_get_line_out_pfx(spec, 0, true, &index);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013180 err = alc268_new_analog_output(spec, nid, name, 0);
13181 if (err < 0)
13182 return err;
13183 }
Kailang Yanga361d842007-06-05 12:30:55 +020013184
13185 nid = cfg->speaker_pins[0];
13186 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013187 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013188 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13189 if (err < 0)
13190 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013191 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013192 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13193 if (err < 0)
13194 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013195 }
13196 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013197 if (nid) {
13198 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13199 if (err < 0)
13200 return err;
13201 }
Kailang Yanga361d842007-06-05 12:30:55 +020013202
13203 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13204 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013205 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013206 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013207 if (err < 0)
13208 return err;
13209 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013210 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013211}
13212
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013213static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13214 hda_nid_t nid, int pin_type)
13215{
13216 int idx;
13217
13218 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai4f574b72011-06-27 16:17:07 +020013219 if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
13220 return;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013221 if (nid == 0x14 || nid == 0x16)
13222 idx = 0;
13223 else
13224 idx = 1;
13225 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13226}
13227
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013228static void alc268_auto_init_dac(struct hda_codec *codec, hda_nid_t nid)
13229{
13230 if (!nid)
13231 return;
13232 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020013233 AMP_OUT_ZERO);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013234}
13235
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013236static void alc268_auto_init_multi_out(struct hda_codec *codec)
13237{
13238 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013239 int i;
13240
13241 for (i = 0; i < spec->autocfg.line_outs; i++) {
13242 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013243 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13244 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13245 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013246 /* mute DACs */
13247 for (i = 0; i < spec->multiout.num_dacs; i++)
13248 alc268_auto_init_dac(codec, spec->multiout.dac_nids[i]);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013249}
13250
13251static void alc268_auto_init_hp_out(struct hda_codec *codec)
13252{
13253 struct alc_spec *spec = codec->spec;
13254 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013255 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013256
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013257 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13258 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013259 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013260 }
13261 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13262 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013263 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013264 }
13265 if (spec->autocfg.mono_out_pin)
13266 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13267 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013268 /* mute DACs */
13269 alc268_auto_init_dac(codec, spec->multiout.hp_nid);
13270 for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
13271 alc268_auto_init_dac(codec, spec->multiout.extra_out_nid[i]);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013272}
13273
Kailang Yanga361d842007-06-05 12:30:55 +020013274static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13275{
13276 struct alc_spec *spec = codec->spec;
13277 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13278 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13279 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13280 unsigned int dac_vol1, dac_vol2;
13281
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013282 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013283 snd_hda_codec_write(codec, speaker_nid, 0,
13284 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013285 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013286 snd_hda_codec_write(codec, 0x0f, 0,
13287 AC_VERB_SET_AMP_GAIN_MUTE,
13288 AMP_IN_UNMUTE(1));
13289 snd_hda_codec_write(codec, 0x10, 0,
13290 AC_VERB_SET_AMP_GAIN_MUTE,
13291 AMP_IN_UNMUTE(1));
13292 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013293 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013294 snd_hda_codec_write(codec, 0x0f, 0,
13295 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13296 snd_hda_codec_write(codec, 0x10, 0,
13297 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13298 }
13299
13300 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013301 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013302 dac_vol2 = AMP_OUT_ZERO;
13303 else if (line_nid == 0x15)
13304 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013305 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013306 dac_vol2 = AMP_OUT_ZERO;
13307 else if (hp_nid == 0x15)
13308 dac_vol1 = AMP_OUT_ZERO;
13309 if (line_nid != 0x16 || hp_nid != 0x16 ||
13310 spec->autocfg.line_out_pins[1] != 0x16 ||
13311 spec->autocfg.line_out_pins[2] != 0x16)
13312 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13313
13314 snd_hda_codec_write(codec, 0x02, 0,
13315 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13316 snd_hda_codec_write(codec, 0x03, 0,
13317 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13318}
13319
Kailang Yanga361d842007-06-05 12:30:55 +020013320/*
13321 * BIOS auto configuration
13322 */
13323static int alc268_parse_auto_config(struct hda_codec *codec)
13324{
13325 struct alc_spec *spec = codec->spec;
13326 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013327 static const hda_nid_t alc268_ignore[] = { 0 };
Kailang Yanga361d842007-06-05 12:30:55 +020013328
13329 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13330 alc268_ignore);
13331 if (err < 0)
13332 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013333 if (!spec->autocfg.line_outs) {
13334 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13335 spec->multiout.max_channels = 2;
13336 spec->no_analog = 1;
13337 goto dig_only;
13338 }
Kailang Yanga361d842007-06-05 12:30:55 +020013339 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013340 }
Kailang Yanga361d842007-06-05 12:30:55 +020013341 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13342 if (err < 0)
13343 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020013344 err = alc_auto_create_input_ctls(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013345 if (err < 0)
13346 return err;
13347
13348 spec->multiout.max_channels = 2;
13349
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013350 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013351 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013352 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013353 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013354 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013355
Takashi Iwai4f574b72011-06-27 16:17:07 +020013356 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
Takashi Iwaid88897e2008-10-31 15:01:37 +010013357 add_mixer(spec, alc268_beep_mixer);
Takashi Iwai4f574b72011-06-27 16:17:07 +020013358 add_verb(spec, alc268_beep_init_verbs);
13359 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013360
Takashi Iwaif970de22011-07-06 17:39:59 +020013361 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013362 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013363
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020013364 if (!spec->dual_adc_switch)
13365 alc_remove_invalid_adc_nids(codec);
13366
Takashi Iwai776e1842007-08-29 15:07:11 +020013367 err = alc_auto_add_mic_boost(codec);
13368 if (err < 0)
13369 return err;
13370
Kailang Yang6227cdc2010-02-25 08:36:52 +010013371 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013372
Kailang Yanga361d842007-06-05 12:30:55 +020013373 return 1;
13374}
13375
Kailang Yanga361d842007-06-05 12:30:55 +020013376/* init callback for auto-configuration model -- overriding the default init */
13377static void alc268_auto_init(struct hda_codec *codec)
13378{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013379 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013380 alc268_auto_init_multi_out(codec);
13381 alc268_auto_init_hp_out(codec);
13382 alc268_auto_init_mono_speaker_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020013383 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020013384 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013385 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013386 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013387 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013388}
13389
13390/*
13391 * configuration and preset
13392 */
Takashi Iwaiea734962011-01-17 11:29:34 +010013393static const char * const alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013394 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013395 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013396 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013397 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013398 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013399 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013400 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013401 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013402#ifdef CONFIG_SND_DEBUG
13403 [ALC268_TEST] = "test",
13404#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013405 [ALC268_AUTO] = "auto",
13406};
13407
Takashi Iwaia9111322011-05-02 11:30:18 +020013408static const struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013409 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013410 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013411 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013412 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013413 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013414 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13415 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013416 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chen0a1896b2011-06-06 18:55:34 -040013417 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013418 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13419 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013420 /* almost compatible with toshiba but with optional digital outs;
13421 * auto-probing seems working fine
13422 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013423 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013424 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013425 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013426 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013427 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013428 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013429 {}
13430};
13431
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013432/* Toshiba laptops have no unique PCI SSID but only codec SSID */
Takashi Iwaia9111322011-05-02 11:30:18 +020013433static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013434 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13435 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13436 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13437 ALC268_TOSHIBA),
13438 {}
13439};
13440
Takashi Iwaia9111322011-05-02 11:30:18 +020013441static const struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013442 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013443 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13444 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013445 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13446 alc267_quanta_il1_verbs },
13447 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13448 .dac_nids = alc268_dac_nids,
13449 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13450 .adc_nids = alc268_adc_nids_alt,
13451 .hp_nid = 0x03,
13452 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13453 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013454 .unsol_event = alc_sku_unsol_event,
13455 .setup = alc267_quanta_il1_setup,
13456 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013457 },
Kailang Yanga361d842007-06-05 12:30:55 +020013458 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013459 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13460 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013461 .init_verbs = { alc268_base_init_verbs },
13462 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13463 .dac_nids = alc268_dac_nids,
13464 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13465 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013466 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013467 .hp_nid = 0x03,
13468 .dig_out_nid = ALC268_DIGOUT_NID,
13469 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13470 .channel_mode = alc268_modes,
13471 .input_mux = &alc268_capture_source,
13472 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013473 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013474 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013475 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013476 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13477 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013478 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13479 .dac_nids = alc268_dac_nids,
13480 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13481 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013482 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013483 .hp_nid = 0x03,
13484 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13485 .channel_mode = alc268_modes,
13486 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013487 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013488 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013489 .init_hook = alc_inithook,
Takashi Iwaid2738092007-08-16 14:59:45 +020013490 },
13491 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013492 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013493 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013494 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13495 alc268_acer_verbs },
13496 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13497 .dac_nids = alc268_dac_nids,
13498 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13499 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013500 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013501 .hp_nid = 0x02,
13502 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13503 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013504 .input_mux = &alc268_acer_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013505 .unsol_event = alc_sku_unsol_event,
13506 .setup = alc268_acer_setup,
13507 .init_hook = alc_inithook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013508 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013509 [ALC268_ACER_DMIC] = {
13510 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13511 alc268_beep_mixer },
13512 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13513 alc268_acer_verbs },
13514 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13515 .dac_nids = alc268_dac_nids,
13516 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13517 .adc_nids = alc268_adc_nids_alt,
13518 .capsrc_nids = alc268_capsrc_nids,
13519 .hp_nid = 0x02,
13520 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13521 .channel_mode = alc268_modes,
13522 .input_mux = &alc268_acer_dmic_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013523 .unsol_event = alc_sku_unsol_event,
13524 .setup = alc268_acer_setup,
13525 .init_hook = alc_inithook,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013526 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013527 [ALC268_ACER_ASPIRE_ONE] = {
13528 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013529 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013530 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013531 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13532 alc268_acer_aspire_one_verbs },
13533 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13534 .dac_nids = alc268_dac_nids,
13535 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13536 .adc_nids = alc268_adc_nids_alt,
13537 .capsrc_nids = alc268_capsrc_nids,
13538 .hp_nid = 0x03,
13539 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13540 .channel_mode = alc268_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013541 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013542 .setup = alc268_acer_lc_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013543 .init_hook = alc_inithook,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013544 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013545 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013546 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13547 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013548 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13549 alc268_dell_verbs },
13550 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13551 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013552 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13553 .adc_nids = alc268_adc_nids_alt,
13554 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013555 .hp_nid = 0x02,
13556 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13557 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013558 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013559 .setup = alc268_dell_setup,
13560 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013561 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013562 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013563 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13564 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013565 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13566 alc268_toshiba_verbs },
13567 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13568 .dac_nids = alc268_dac_nids,
13569 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13570 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013571 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013572 .hp_nid = 0x03,
13573 .dig_out_nid = ALC268_DIGOUT_NID,
13574 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13575 .channel_mode = alc268_modes,
13576 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013577 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013578 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013579 .init_hook = alc_inithook,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013580 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013581#ifdef CONFIG_SND_DEBUG
13582 [ALC268_TEST] = {
13583 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13584 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013585 alc268_volume_init_verbs,
13586 alc268_beep_init_verbs },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013587 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13588 .dac_nids = alc268_dac_nids,
13589 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13590 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013591 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013592 .hp_nid = 0x03,
13593 .dig_out_nid = ALC268_DIGOUT_NID,
13594 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13595 .channel_mode = alc268_modes,
13596 .input_mux = &alc268_capture_source,
13597 },
13598#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013599};
13600
13601static int patch_alc268(struct hda_codec *codec)
13602{
13603 struct alc_spec *spec;
13604 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013605 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013606
Julia Lawallef86f582009-12-19 08:18:03 +010013607 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013608 if (spec == NULL)
13609 return -ENOMEM;
13610
13611 codec->spec = spec;
13612
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013613 /* ALC268 has no aa-loopback mixer */
13614
Kailang Yanga361d842007-06-05 12:30:55 +020013615 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13616 alc268_models,
13617 alc268_cfg_tbl);
13618
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013619 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13620 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013621 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013622
Kailang Yanga361d842007-06-05 12:30:55 +020013623 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013624 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13625 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013626 board_config = ALC268_AUTO;
13627 }
13628
13629 if (board_config == ALC268_AUTO) {
13630 /* automatic parse from the BIOS config */
13631 err = alc268_parse_auto_config(codec);
13632 if (err < 0) {
13633 alc_free(codec);
13634 return err;
13635 } else if (!err) {
13636 printk(KERN_INFO
13637 "hda_codec: Cannot set up configuration "
13638 "from BIOS. Using base mode...\n");
13639 board_config = ALC268_3ST;
13640 }
13641 }
13642
13643 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013644 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013645
Takashi Iwai22971e32009-02-10 11:56:44 +010013646 has_beep = 0;
13647 for (i = 0; i < spec->num_mixers; i++) {
13648 if (spec->mixers[i] == alc268_beep_mixer) {
13649 has_beep = 1;
13650 break;
13651 }
13652 }
13653
13654 if (has_beep) {
13655 err = snd_hda_attach_beep_device(codec, 0x1);
13656 if (err < 0) {
13657 alc_free(codec);
13658 return err;
13659 }
13660 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13661 /* override the amp caps for beep generator */
13662 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013663 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13664 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13665 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13666 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013667 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013668
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013669 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020013670 alc_auto_fill_adc_caps(codec);
13671 alc_remove_invalid_adc_nids(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013672 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013673
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020013674 if (!spec->cap_mixer && !spec->no_analog)
13675 set_capture_mixer(codec);
13676
Takashi Iwai2134ea42008-01-10 16:53:55 +010013677 spec->vmaster_nid = 0x02;
13678
Kailang Yanga361d842007-06-05 12:30:55 +020013679 codec->patch_ops = alc_patch_ops;
13680 if (board_config == ALC268_AUTO)
13681 spec->init_hook = alc268_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020013682 spec->shutup = alc_eapd_shutup;
Kailang Yangea1fb292008-08-26 12:58:38 +020013683
Kailang Yangbf1b0222010-10-21 08:49:56 +020013684 alc_init_jacks(codec);
13685
Kailang Yanga361d842007-06-05 12:30:55 +020013686 return 0;
13687}
13688
13689/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013690 * ALC269 channel source setting (2 channel)
13691 */
13692#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13693
13694#define alc269_dac_nids alc260_dac_nids
13695
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013696static const hda_nid_t alc269_adc_nids[1] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010013697 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013698 0x08,
13699};
13700
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013701static const hda_nid_t alc269_capsrc_nids[1] = {
Takashi Iwaie01bf502008-08-21 16:25:07 +020013702 0x23,
13703};
13704
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013705static const hda_nid_t alc269vb_adc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013706 /* ADC1 */
13707 0x09,
13708};
13709
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013710static const hda_nid_t alc269vb_capsrc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013711 0x22,
13712};
13713
Kailang Yangf6a92242007-12-13 16:52:54 +010013714#define alc269_modes alc260_modes
13715#define alc269_capture_source alc880_lg_lw_capture_source
13716
Takashi Iwaia9111322011-05-02 11:30:18 +020013717static const struct snd_kcontrol_new alc269_base_mixer[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010013718 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13719 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13720 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13721 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13722 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13723 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013724 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010013725 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13726 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013727 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010013728 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13729 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13730 { } /* end */
13731};
13732
Takashi Iwaia9111322011-05-02 11:30:18 +020013733static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013734 /* output mixer control */
13735 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13736 {
13737 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13738 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013739 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013740 .info = snd_hda_mixer_amp_switch_info,
13741 .get = snd_hda_mixer_amp_switch_get,
13742 .put = alc268_acer_master_sw_put,
13743 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13744 },
13745 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13746 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013747 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013748 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13749 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013750 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013751 { }
13752};
13753
Takashi Iwaia9111322011-05-02 11:30:18 +020013754static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
Tony Vroon64154832008-11-06 15:08:49 +000013755 /* output mixer control */
13756 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13757 {
13758 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13759 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013760 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013761 .info = snd_hda_mixer_amp_switch_info,
13762 .get = snd_hda_mixer_amp_switch_get,
13763 .put = alc268_acer_master_sw_put,
13764 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13765 },
13766 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13767 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013768 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013769 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13770 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013771 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013772 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13773 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013774 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013775 { }
13776};
13777
Takashi Iwaia9111322011-05-02 11:30:18 +020013778static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013779 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013780 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013781 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013782 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013783 { } /* end */
13784};
13785
Takashi Iwaia9111322011-05-02 11:30:18 +020013786static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013787 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13788 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13789 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13790 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13791 { } /* end */
13792};
13793
Takashi Iwaia9111322011-05-02 11:30:18 +020013794static const struct snd_kcontrol_new alc269_asus_mixer[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020013795 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13796 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
13797 { } /* end */
13798};
13799
Kailang Yangf6a92242007-12-13 16:52:54 +010013800/* capture mixer elements */
Takashi Iwaia9111322011-05-02 11:30:18 +020013801static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013802 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13803 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013804 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13805 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013806 { } /* end */
13807};
13808
Takashi Iwaia9111322011-05-02 11:30:18 +020013809static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013810 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13811 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013812 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013813 { } /* end */
13814};
13815
Takashi Iwaia9111322011-05-02 11:30:18 +020013816static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013817 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13818 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013819 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13820 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013821 { } /* end */
13822};
13823
Takashi Iwaia9111322011-05-02 11:30:18 +020013824static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013825 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13826 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013827 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013828 { } /* end */
13829};
13830
Takashi Iwai26f5df22008-11-03 17:39:46 +010013831/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013832#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013833
Takashi Iwaia9111322011-05-02 11:30:18 +020013834static const struct hda_verb alc269_quanta_fl1_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013835 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13836 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13837 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13838 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13839 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13840 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13841 { }
13842};
13843
Takashi Iwaia9111322011-05-02 11:30:18 +020013844static const struct hda_verb alc269_lifebook_verbs[] = {
Tony Vroon64154832008-11-06 15:08:49 +000013845 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13846 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13847 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13848 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13849 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13850 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13851 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13852 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13853 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13854 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13855 { }
13856};
13857
Kailang Yang60db6b52008-08-26 13:13:00 +020013858/* toggle speaker-output according to the hp-jack state */
13859static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13860{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013861 alc_hp_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013862
13863 snd_hda_codec_write(codec, 0x20, 0,
13864 AC_VERB_SET_COEF_INDEX, 0x0c);
13865 snd_hda_codec_write(codec, 0x20, 0,
13866 AC_VERB_SET_PROC_COEF, 0x680);
13867
13868 snd_hda_codec_write(codec, 0x20, 0,
13869 AC_VERB_SET_COEF_INDEX, 0x0c);
13870 snd_hda_codec_write(codec, 0x20, 0,
13871 AC_VERB_SET_PROC_COEF, 0x480);
13872}
13873
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013874#define alc269_lifebook_speaker_automute \
13875 alc269_quanta_fl1_speaker_automute
Tony Vroon64154832008-11-06 15:08:49 +000013876
Tony Vroon64154832008-11-06 15:08:49 +000013877static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13878{
13879 unsigned int present_laptop;
13880 unsigned int present_dock;
13881
Wu Fengguang864f92b2009-11-18 12:38:02 +080013882 present_laptop = snd_hda_jack_detect(codec, 0x18);
13883 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013884
13885 /* Laptop mic port overrides dock mic port, design decision */
13886 if (present_dock)
13887 snd_hda_codec_write(codec, 0x23, 0,
13888 AC_VERB_SET_CONNECT_SEL, 0x3);
13889 if (present_laptop)
13890 snd_hda_codec_write(codec, 0x23, 0,
13891 AC_VERB_SET_CONNECT_SEL, 0x0);
13892 if (!present_dock && !present_laptop)
13893 snd_hda_codec_write(codec, 0x23, 0,
13894 AC_VERB_SET_CONNECT_SEL, 0x1);
13895}
13896
Kailang Yang60db6b52008-08-26 13:13:00 +020013897static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13898 unsigned int res)
13899{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013900 switch (res >> 26) {
13901 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013902 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013903 break;
13904 case ALC880_MIC_EVENT:
13905 alc_mic_automute(codec);
13906 break;
13907 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013908}
13909
Tony Vroon64154832008-11-06 15:08:49 +000013910static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13911 unsigned int res)
13912{
13913 if ((res >> 26) == ALC880_HP_EVENT)
13914 alc269_lifebook_speaker_automute(codec);
13915 if ((res >> 26) == ALC880_MIC_EVENT)
13916 alc269_lifebook_mic_autoswitch(codec);
13917}
13918
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013919static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13920{
13921 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010013922 spec->autocfg.hp_pins[0] = 0x15;
13923 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013924 spec->automute_mixer_nid[0] = 0x0c;
13925 spec->automute = 1;
13926 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013927 spec->ext_mic.pin = 0x18;
13928 spec->ext_mic.mux_idx = 0;
13929 spec->int_mic.pin = 0x19;
13930 spec->int_mic.mux_idx = 1;
13931 spec->auto_mic = 1;
13932}
13933
Kailang Yang60db6b52008-08-26 13:13:00 +020013934static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13935{
13936 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013937 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013938}
13939
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013940static void alc269_lifebook_setup(struct hda_codec *codec)
13941{
13942 struct alc_spec *spec = codec->spec;
13943 spec->autocfg.hp_pins[0] = 0x15;
13944 spec->autocfg.hp_pins[1] = 0x1a;
13945 spec->autocfg.speaker_pins[0] = 0x14;
13946 spec->automute_mixer_nid[0] = 0x0c;
13947 spec->automute = 1;
13948 spec->automute_mode = ALC_AUTOMUTE_MIXER;
13949}
13950
Tony Vroon64154832008-11-06 15:08:49 +000013951static void alc269_lifebook_init_hook(struct hda_codec *codec)
13952{
13953 alc269_lifebook_speaker_automute(codec);
13954 alc269_lifebook_mic_autoswitch(codec);
13955}
13956
Takashi Iwaia9111322011-05-02 11:30:18 +020013957static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013958 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13959 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
13960 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13961 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13962 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13963 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13964 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13965 {}
13966};
13967
Takashi Iwaia9111322011-05-02 11:30:18 +020013968static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013969 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13970 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
13971 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13972 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
13973 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13974 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13975 {}
13976};
13977
Takashi Iwaia9111322011-05-02 11:30:18 +020013978static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013979 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13980 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
13981 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13982 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13983 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13984 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13985 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13986 {}
13987};
13988
Takashi Iwaia9111322011-05-02 11:30:18 +020013989static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013990 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13991 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
13992 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13993 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13994 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13995 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13996 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13997 {}
13998};
13999
Takashi Iwaia9111322011-05-02 11:30:18 +020014000static const struct hda_verb alc271_acer_dmic_verbs[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014001 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14002 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14003 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14004 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14005 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14006 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14007 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14008 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14009 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14010 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14011 { }
14012};
14013
Kailang Yang226b1ec2010-04-09 11:01:20 +020014014static void alc269_laptop_amic_setup(struct hda_codec *codec)
14015{
14016 struct alc_spec *spec = codec->spec;
14017 spec->autocfg.hp_pins[0] = 0x15;
14018 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014019 spec->automute_mixer_nid[0] = 0x0c;
14020 spec->automute = 1;
14021 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014022 spec->ext_mic.pin = 0x18;
14023 spec->ext_mic.mux_idx = 0;
14024 spec->int_mic.pin = 0x19;
14025 spec->int_mic.mux_idx = 1;
14026 spec->auto_mic = 1;
14027}
14028
Kailang Yang84898e82010-02-04 14:16:14 +010014029static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014030{
14031 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014032 spec->autocfg.hp_pins[0] = 0x15;
14033 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014034 spec->automute_mixer_nid[0] = 0x0c;
14035 spec->automute = 1;
14036 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014037 spec->ext_mic.pin = 0x18;
14038 spec->ext_mic.mux_idx = 0;
14039 spec->int_mic.pin = 0x12;
14040 spec->int_mic.mux_idx = 5;
14041 spec->auto_mic = 1;
14042}
14043
Kailang Yang226b1ec2010-04-09 11:01:20 +020014044static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014045{
14046 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014047 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014048 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014049 spec->automute_mixer_nid[0] = 0x0c;
14050 spec->automute = 1;
14051 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014052 spec->ext_mic.pin = 0x18;
14053 spec->ext_mic.mux_idx = 0;
14054 spec->int_mic.pin = 0x19;
14055 spec->int_mic.mux_idx = 1;
14056 spec->auto_mic = 1;
14057}
14058
Kailang Yang226b1ec2010-04-09 11:01:20 +020014059static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14060{
14061 struct alc_spec *spec = codec->spec;
14062 spec->autocfg.hp_pins[0] = 0x21;
14063 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014064 spec->automute_mixer_nid[0] = 0x0c;
14065 spec->automute = 1;
14066 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014067 spec->ext_mic.pin = 0x18;
14068 spec->ext_mic.mux_idx = 0;
14069 spec->int_mic.pin = 0x12;
14070 spec->int_mic.mux_idx = 6;
14071 spec->auto_mic = 1;
14072}
14073
Kailang Yangf6a92242007-12-13 16:52:54 +010014074/*
14075 * generic initialization of ADC, input mixers and output mixers
14076 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014077static const struct hda_verb alc269_init_verbs[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014078 /*
14079 * Unmute ADC0 and set the default input to mic-in
14080 */
Kailang Yang84898e82010-02-04 14:16:14 +010014081 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014082
14083 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014084 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014085 */
14086 /* set vol=0 to output mixers */
14087 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14088 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14089
14090 /* set up input amps for analog loopback */
14091 /* Amp Indices: DAC = 0, mixer = 1 */
14092 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14093 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14094 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14095 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14096 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14097 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14098
14099 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14100 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14101 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14102 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14103 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14104 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14105 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14106
14107 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14108 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014109
Kailang Yang84898e82010-02-04 14:16:14 +010014110 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014111 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14112 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014113 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014114
14115 /* set EAPD */
14116 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014117 { }
14118};
14119
Takashi Iwaia9111322011-05-02 11:30:18 +020014120static const struct hda_verb alc269vb_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014121 /*
14122 * Unmute ADC0 and set the default input to mic-in
14123 */
14124 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14125
14126 /*
14127 * Set up output mixers (0x02 - 0x03)
14128 */
14129 /* set vol=0 to output mixers */
14130 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14131 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14132
14133 /* set up input amps for analog loopback */
14134 /* Amp Indices: DAC = 0, mixer = 1 */
14135 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14136 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14137 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14138 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14139 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14140 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14141
14142 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14143 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14144 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14145 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14146 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14147 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14148 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14149
14150 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14151 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14152
14153 /* FIXME: use Mux-type input source selection */
14154 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14155 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14156 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14157
14158 /* set EAPD */
14159 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014160 { }
14161};
14162
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014163#define alc269_auto_create_multi_out_ctls \
14164 alc268_auto_create_multi_out_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014165
14166#ifdef CONFIG_SND_HDA_POWER_SAVE
14167#define alc269_loopbacks alc880_loopbacks
14168#endif
14169
Takashi Iwaia9111322011-05-02 11:30:18 +020014170static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014171 .substreams = 1,
14172 .channels_min = 2,
14173 .channels_max = 8,
14174 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14175 /* NID is set in alc_build_pcms */
14176 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +020014177 .open = alc_playback_pcm_open,
14178 .prepare = alc_playback_pcm_prepare,
14179 .cleanup = alc_playback_pcm_cleanup
Takashi Iwaif03d3112009-03-05 14:18:16 +010014180 },
14181};
14182
Takashi Iwaia9111322011-05-02 11:30:18 +020014183static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014184 .substreams = 1,
14185 .channels_min = 2,
14186 .channels_max = 2,
14187 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14188 /* NID is set in alc_build_pcms */
14189};
14190
Takashi Iwaiad358792010-03-30 18:00:59 +020014191#ifdef CONFIG_SND_HDA_POWER_SAVE
14192static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14193{
14194 switch (codec->subsystem_id) {
14195 case 0x103c1586:
14196 return 1;
14197 }
14198 return 0;
14199}
14200
14201static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14202{
14203 /* update mute-LED according to the speaker mute state */
14204 if (nid == 0x01 || nid == 0x14) {
14205 int pinval;
14206 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14207 HDA_AMP_MUTE)
14208 pinval = 0x24;
14209 else
14210 pinval = 0x20;
14211 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014212 snd_hda_codec_update_cache(codec, 0x19, 0,
14213 AC_VERB_SET_PIN_WIDGET_CONTROL,
14214 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014215 }
14216 return alc_check_power_status(codec, nid);
14217}
14218#endif /* CONFIG_SND_HDA_POWER_SAVE */
14219
Takashi Iwai840b64c2010-07-13 22:49:01 +020014220static int alc275_setup_dual_adc(struct hda_codec *codec)
14221{
14222 struct alc_spec *spec = codec->spec;
14223
14224 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14225 return 0;
14226 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14227 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14228 if (spec->ext_mic.pin <= 0x12) {
14229 spec->private_adc_nids[0] = 0x08;
14230 spec->private_adc_nids[1] = 0x11;
14231 spec->private_capsrc_nids[0] = 0x23;
14232 spec->private_capsrc_nids[1] = 0x22;
14233 } else {
14234 spec->private_adc_nids[0] = 0x11;
14235 spec->private_adc_nids[1] = 0x08;
14236 spec->private_capsrc_nids[0] = 0x22;
14237 spec->private_capsrc_nids[1] = 0x23;
14238 }
14239 spec->adc_nids = spec->private_adc_nids;
14240 spec->capsrc_nids = spec->private_capsrc_nids;
14241 spec->num_adc_nids = 2;
14242 spec->dual_adc_switch = 1;
14243 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14244 spec->adc_nids[0], spec->adc_nids[1]);
14245 return 1;
14246 }
14247 return 0;
14248}
14249
Takashi Iwaid433a672010-09-20 15:11:54 +020014250/* different alc269-variants */
14251enum {
Kailang Yangb6878572011-07-06 09:51:29 +020014252 ALC269_TYPE_ALC269VA,
Kailang Yang48c88e82010-11-23 08:56:16 +010014253 ALC269_TYPE_ALC269VB,
Kailang Yangb6878572011-07-06 09:51:29 +020014254 ALC269_TYPE_ALC269VC,
Takashi Iwaid433a672010-09-20 15:11:54 +020014255};
14256
Kailang Yangf6a92242007-12-13 16:52:54 +010014257/*
14258 * BIOS auto configuration
14259 */
14260static int alc269_parse_auto_config(struct hda_codec *codec)
14261{
14262 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014263 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014264 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Kailang Yangf6a92242007-12-13 16:52:54 +010014265
14266 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14267 alc269_ignore);
14268 if (err < 0)
14269 return err;
14270
14271 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14272 if (err < 0)
14273 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020014274 err = alc_auto_create_input_ctls(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014275 if (err < 0)
14276 return err;
14277
14278 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14279
Takashi Iwai757899a2010-07-30 10:48:14 +020014280 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014281
Takashi Iwai603c4012008-07-30 15:01:44 +020014282 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014283 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014284
Kailang Yangb6878572011-07-06 09:51:29 +020014285 if (spec->codec_variant != ALC269_TYPE_ALC269VA)
Kailang Yang6227cdc2010-02-25 08:36:52 +010014286 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020014287 else
Kailang Yang6227cdc2010-02-25 08:36:52 +010014288 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014289
Kailang Yangf6a92242007-12-13 16:52:54 +010014290 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014291 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014292
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020014293 alc275_setup_dual_adc(codec);
14294 if (!spec->dual_adc_switch)
14295 alc_remove_invalid_adc_nids(codec);
Takashi Iwai66946352010-03-29 17:21:45 +020014296
Kailang Yangf6a92242007-12-13 16:52:54 +010014297 err = alc_auto_add_mic_boost(codec);
14298 if (err < 0)
14299 return err;
14300
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014301 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014302 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014303
Kailang Yangf6a92242007-12-13 16:52:54 +010014304 return 1;
14305}
14306
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014307#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14308#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014309
14310
14311/* init callback for auto-configuration model -- overriding the default init */
14312static void alc269_auto_init(struct hda_codec *codec)
14313{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014314 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014315 alc269_auto_init_multi_out(codec);
14316 alc269_auto_init_hp_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020014317 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020014318 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014319 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014320 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014321 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014322}
14323
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014324static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14325{
14326 int val = alc_read_coef_idx(codec, 0x04);
14327 if (power_up)
14328 val |= 1 << 11;
14329 else
14330 val &= ~(1 << 11);
14331 alc_write_coef_idx(codec, 0x04, val);
14332}
14333
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014334static void alc269_shutup(struct hda_codec *codec)
Kailang Yang977ddd62010-09-15 10:02:29 +020014335{
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014336 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14337 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014338 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014339 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014340 msleep(150);
14341 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014342}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014343
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014344#ifdef SND_HDA_NEEDS_RESUME
Kailang Yang977ddd62010-09-15 10:02:29 +020014345static int alc269_resume(struct hda_codec *codec)
14346{
Kailang Yang977ddd62010-09-15 10:02:29 +020014347 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014348 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014349 msleep(150);
14350 }
14351
14352 codec->patch_ops.init(codec);
14353
14354 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014355 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014356 msleep(200);
14357 }
14358
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014359 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14360 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014361
14362 snd_hda_codec_resume_amp(codec);
14363 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014364 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014365 return 0;
14366}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014367#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014368
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014369static void alc269_fixup_hweq(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014370 const struct alc_fixup *fix, int action)
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014371{
14372 int coef;
14373
Takashi Iwai58701122011-01-13 15:41:45 +010014374 if (action != ALC_FIXUP_ACT_INIT)
Takashi Iwai9fb1ef22011-01-13 14:40:43 +010014375 return;
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014376 coef = alc_read_coef_idx(codec, 0x1e);
14377 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
14378}
14379
Takashi Iwai6981d182011-04-15 10:11:12 +020014380static void alc271_fixup_dmic(struct hda_codec *codec,
14381 const struct alc_fixup *fix, int action)
14382{
Takashi Iwaia9111322011-05-02 11:30:18 +020014383 static const struct hda_verb verbs[] = {
Takashi Iwai6981d182011-04-15 10:11:12 +020014384 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14385 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14386 {}
14387 };
14388 unsigned int cfg;
14389
14390 if (strcmp(codec->chip_name, "ALC271X"))
14391 return;
14392 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
14393 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
14394 snd_hda_sequence_write(codec, verbs);
14395}
14396
Takashi Iwaiff818c22010-04-12 08:59:25 +020014397enum {
14398 ALC269_FIXUP_SONY_VAIO,
Takashi Iwai74dc8902011-01-13 14:14:41 +010014399 ALC275_FIXUP_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014400 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014401 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014402 ALC269_FIXUP_ASUS_G73JW,
Kailang Yang357f9152011-01-12 08:12:52 +010014403 ALC269_FIXUP_LENOVO_EAPD,
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014404 ALC275_FIXUP_SONY_HWEQ,
Takashi Iwai6981d182011-04-15 10:11:12 +020014405 ALC271_FIXUP_DMIC,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014406};
14407
Takashi Iwaiff818c22010-04-12 08:59:25 +020014408static const struct alc_fixup alc269_fixups[] = {
14409 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014410 .type = ALC_FIXUP_VERBS,
14411 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020014412 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14413 {}
14414 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014415 },
Takashi Iwai74dc8902011-01-13 14:14:41 +010014416 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014417 .type = ALC_FIXUP_VERBS,
14418 .v.verbs = (const struct hda_verb[]) {
Kailang Yang27855912010-12-21 09:09:53 +010014419 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14420 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14421 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14422 { }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014423 },
14424 .chained = true,
14425 .chain_id = ALC269_FIXUP_SONY_VAIO
Kailang Yang27855912010-12-21 09:09:53 +010014426 },
David Henningsson145a9022010-09-16 10:07:53 +020014427 [ALC269_FIXUP_DELL_M101Z] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014428 .type = ALC_FIXUP_VERBS,
14429 .v.verbs = (const struct hda_verb[]) {
David Henningsson145a9022010-09-16 10:07:53 +020014430 /* Enables internal speaker */
14431 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14432 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14433 {}
14434 }
14435 },
David Henningsson022c92b2010-12-17 20:43:04 +010014436 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014437 .type = ALC_FIXUP_SKU,
14438 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonfe67b242010-12-15 08:01:46 +010014439 },
David Henningssonac612402010-12-15 09:18:18 +010014440 [ALC269_FIXUP_ASUS_G73JW] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014441 .type = ALC_FIXUP_PINS,
14442 .v.pins = (const struct alc_pincfg[]) {
David Henningssonac612402010-12-15 09:18:18 +010014443 { 0x17, 0x99130111 }, /* subwoofer */
14444 { }
14445 }
14446 },
Kailang Yang357f9152011-01-12 08:12:52 +010014447 [ALC269_FIXUP_LENOVO_EAPD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014448 .type = ALC_FIXUP_VERBS,
14449 .v.verbs = (const struct hda_verb[]) {
Kailang Yang357f9152011-01-12 08:12:52 +010014450 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
14451 {}
14452 }
14453 },
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014454 [ALC275_FIXUP_SONY_HWEQ] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014455 .type = ALC_FIXUP_FUNC,
14456 .v.func = alc269_fixup_hweq,
14457 .chained = true,
14458 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
Takashi Iwai6981d182011-04-15 10:11:12 +020014459 },
14460 [ALC271_FIXUP_DMIC] = {
14461 .type = ALC_FIXUP_FUNC,
14462 .v.func = alc271_fixup_dmic,
14463 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014464};
14465
Takashi Iwaia9111322011-05-02 11:30:18 +020014466static const struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai74dc8902011-01-13 14:14:41 +010014467 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014468 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
14469 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
Takashi Iwai7039c742010-12-23 16:35:34 +010014470 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014471 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Takashi Iwai6981d182011-04-15 10:11:12 +020014472 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
David Henningsson022c92b2010-12-17 20:43:04 +010014473 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonded9f522011-01-26 11:46:12 +010014474 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
14475 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
14476 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
14477 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014478 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Kailang Yang357f9152011-01-12 08:12:52 +010014479 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014480 {}
14481};
14482
14483
Kailang Yangf6a92242007-12-13 16:52:54 +010014484/*
14485 * configuration and preset
14486 */
Takashi Iwaiea734962011-01-17 11:29:34 +010014487static const char * const alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014488 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014489 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014490 [ALC269_AMIC] = "laptop-amic",
14491 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014492 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014493 [ALC269_LIFEBOOK] = "lifebook",
14494 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014495};
14496
Takashi Iwaia9111322011-05-02 11:30:18 +020014497static const struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014498 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014499 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020014500 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014501 ALC269_AMIC),
14502 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14503 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14504 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14505 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14506 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14507 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14508 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14509 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14510 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
Chih-Wei Huangc790ad32011-02-25 11:14:31 +080014511 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
Kailang Yang84898e82010-02-04 14:16:14 +010014512 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14513 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14514 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14515 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14516 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14517 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14518 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14519 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14520 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14521 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14522 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14523 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14524 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14525 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14526 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14527 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14528 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14529 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14530 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14531 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14532 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14533 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14534 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14535 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14536 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14537 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014538 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014539 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014540 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014541 ALC269_DMIC),
14542 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14543 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014544 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014545 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014546 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14547 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14548 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14549 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14550 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14551 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014552 {}
14553};
14554
Takashi Iwaia9111322011-05-02 11:30:18 +020014555static const struct alc_config_preset alc269_presets[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014556 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014557 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014558 .init_verbs = { alc269_init_verbs },
14559 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14560 .dac_nids = alc269_dac_nids,
14561 .hp_nid = 0x03,
14562 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14563 .channel_mode = alc269_modes,
14564 .input_mux = &alc269_capture_source,
14565 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014566 [ALC269_QUANTA_FL1] = {
14567 .mixers = { alc269_quanta_fl1_mixer },
14568 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14569 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14570 .dac_nids = alc269_dac_nids,
14571 .hp_nid = 0x03,
14572 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14573 .channel_mode = alc269_modes,
14574 .input_mux = &alc269_capture_source,
14575 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014576 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014577 .init_hook = alc269_quanta_fl1_init_hook,
14578 },
Kailang Yang84898e82010-02-04 14:16:14 +010014579 [ALC269_AMIC] = {
14580 .mixers = { alc269_laptop_mixer },
14581 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014582 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014583 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014584 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14585 .dac_nids = alc269_dac_nids,
14586 .hp_nid = 0x03,
14587 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14588 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014589 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014590 .setup = alc269_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014591 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014592 },
Kailang Yang84898e82010-02-04 14:16:14 +010014593 [ALC269_DMIC] = {
14594 .mixers = { alc269_laptop_mixer },
14595 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014596 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014597 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014598 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14599 .dac_nids = alc269_dac_nids,
14600 .hp_nid = 0x03,
14601 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14602 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014603 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014604 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014605 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010014606 },
14607 [ALC269VB_AMIC] = {
14608 .mixers = { alc269vb_laptop_mixer },
14609 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14610 .init_verbs = { alc269vb_init_verbs,
14611 alc269vb_laptop_amic_init_verbs },
14612 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14613 .dac_nids = alc269_dac_nids,
14614 .hp_nid = 0x03,
14615 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14616 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014617 .unsol_event = alc_sku_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014618 .setup = alc269vb_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014619 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010014620 },
14621 [ALC269VB_DMIC] = {
14622 .mixers = { alc269vb_laptop_mixer },
14623 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14624 .init_verbs = { alc269vb_init_verbs,
14625 alc269vb_laptop_dmic_init_verbs },
14626 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14627 .dac_nids = alc269_dac_nids,
14628 .hp_nid = 0x03,
14629 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14630 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014631 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014632 .setup = alc269vb_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014633 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014634 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014635 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014636 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014637 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014638 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014639 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014640 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14641 .dac_nids = alc269_dac_nids,
14642 .hp_nid = 0x03,
14643 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14644 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014645 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014646 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014647 .init_hook = alc_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014648 },
Tony Vroon64154832008-11-06 15:08:49 +000014649 [ALC269_LIFEBOOK] = {
14650 .mixers = { alc269_lifebook_mixer },
14651 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14652 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14653 .dac_nids = alc269_dac_nids,
14654 .hp_nid = 0x03,
14655 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14656 .channel_mode = alc269_modes,
14657 .input_mux = &alc269_capture_source,
14658 .unsol_event = alc269_lifebook_unsol_event,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014659 .setup = alc269_lifebook_setup,
Tony Vroon64154832008-11-06 15:08:49 +000014660 .init_hook = alc269_lifebook_init_hook,
14661 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014662 [ALC271_ACER] = {
14663 .mixers = { alc269_asus_mixer },
14664 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14665 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
14666 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14667 .dac_nids = alc269_dac_nids,
14668 .adc_nids = alc262_dmic_adc_nids,
14669 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
14670 .capsrc_nids = alc262_dmic_capsrc_nids,
14671 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14672 .channel_mode = alc269_modes,
14673 .input_mux = &alc269_capture_source,
14674 .dig_out_nid = ALC880_DIGOUT_NID,
14675 .unsol_event = alc_sku_unsol_event,
14676 .setup = alc269vb_laptop_dmic_setup,
14677 .init_hook = alc_inithook,
14678 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014679};
14680
Kailang Yang977ddd62010-09-15 10:02:29 +020014681static int alc269_fill_coef(struct hda_codec *codec)
14682{
14683 int val;
14684
14685 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
14686 alc_write_coef_idx(codec, 0xf, 0x960b);
14687 alc_write_coef_idx(codec, 0xe, 0x8817);
14688 }
14689
14690 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
14691 alc_write_coef_idx(codec, 0xf, 0x960b);
14692 alc_write_coef_idx(codec, 0xe, 0x8814);
14693 }
14694
14695 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
14696 val = alc_read_coef_idx(codec, 0x04);
14697 /* Power up output pin */
14698 alc_write_coef_idx(codec, 0x04, val | (1<<11));
14699 }
14700
14701 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
14702 val = alc_read_coef_idx(codec, 0xd);
14703 if ((val & 0x0c00) >> 10 != 0x1) {
14704 /* Capless ramp up clock control */
Kailang Yangb896b4e2011-05-18 11:53:16 +020014705 alc_write_coef_idx(codec, 0xd, val | (1<<10));
Kailang Yang977ddd62010-09-15 10:02:29 +020014706 }
14707 val = alc_read_coef_idx(codec, 0x17);
14708 if ((val & 0x01c0) >> 6 != 0x4) {
14709 /* Class D power on reset */
Kailang Yangb896b4e2011-05-18 11:53:16 +020014710 alc_write_coef_idx(codec, 0x17, val | (1<<7));
Kailang Yang977ddd62010-09-15 10:02:29 +020014711 }
14712 }
Kailang Yangb896b4e2011-05-18 11:53:16 +020014713
14714 val = alc_read_coef_idx(codec, 0xd); /* Class D */
14715 alc_write_coef_idx(codec, 0xd, val | (1<<14));
14716
14717 val = alc_read_coef_idx(codec, 0x4); /* HP */
14718 alc_write_coef_idx(codec, 0x4, val | (1<<11));
14719
Kailang Yang977ddd62010-09-15 10:02:29 +020014720 return 0;
14721}
14722
Kailang Yangf6a92242007-12-13 16:52:54 +010014723static int patch_alc269(struct hda_codec *codec)
14724{
14725 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010014726 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010014727 int err;
14728
14729 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14730 if (spec == NULL)
14731 return -ENOMEM;
14732
14733 codec->spec = spec;
14734
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020014735 spec->mixer_nid = 0x0b;
14736
Kailang Yangda00c242010-03-19 11:23:45 +010014737 alc_auto_parse_customize_define(codec);
14738
Kailang Yangc793bec2010-12-21 09:14:13 +010014739 if (codec->vendor_id == 0x10ec0269) {
Kailang Yangb6878572011-07-06 09:51:29 +020014740 spec->codec_variant = ALC269_TYPE_ALC269VA;
Kailang Yangc793bec2010-12-21 09:14:13 +010014741 coef = alc_read_coef_idx(codec, 0);
14742 if ((coef & 0x00f0) == 0x0010) {
14743 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14744 spec->cdefine.platform_type == 1) {
14745 alc_codec_rename(codec, "ALC271X");
Kailang Yangc793bec2010-12-21 09:14:13 +010014746 } else if ((coef & 0xf000) == 0x2000) {
14747 alc_codec_rename(codec, "ALC259");
Kailang Yangc793bec2010-12-21 09:14:13 +010014748 } else if ((coef & 0xf000) == 0x3000) {
14749 alc_codec_rename(codec, "ALC258");
Kailang Yangb6878572011-07-06 09:51:29 +020014750 } else if ((coef & 0xfff0) == 0x3010) {
14751 alc_codec_rename(codec, "ALC277");
Kailang Yangc793bec2010-12-21 09:14:13 +010014752 } else {
14753 alc_codec_rename(codec, "ALC269VB");
Kailang Yangc793bec2010-12-21 09:14:13 +010014754 }
Kailang Yangb6878572011-07-06 09:51:29 +020014755 spec->codec_variant = ALC269_TYPE_ALC269VB;
14756 } else if ((coef & 0x00f0) == 0x0020) {
14757 if (coef == 0xa023)
14758 alc_codec_rename(codec, "ALC259");
14759 else if (coef == 0x6023)
14760 alc_codec_rename(codec, "ALC281X");
14761 else if (codec->bus->pci->subsystem_vendor == 0x17aa &&
14762 codec->bus->pci->subsystem_device == 0x21f3)
14763 alc_codec_rename(codec, "ALC3202");
14764 else
14765 alc_codec_rename(codec, "ALC269VC");
14766 spec->codec_variant = ALC269_TYPE_ALC269VC;
Kailang Yangc793bec2010-12-21 09:14:13 +010014767 } else
14768 alc_fix_pll_init(codec, 0x20, 0x04, 15);
14769 alc269_fill_coef(codec);
14770 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014771
Kailang Yangf6a92242007-12-13 16:52:54 +010014772 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14773 alc269_models,
14774 alc269_cfg_tbl);
14775
14776 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014777 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14778 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014779 board_config = ALC269_AUTO;
14780 }
14781
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014782 if (board_config == ALC269_AUTO) {
14783 alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
14784 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
14785 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014786
Kailang Yangf6a92242007-12-13 16:52:54 +010014787 if (board_config == ALC269_AUTO) {
14788 /* automatic parse from the BIOS config */
14789 err = alc269_parse_auto_config(codec);
14790 if (err < 0) {
14791 alc_free(codec);
14792 return err;
14793 } else if (!err) {
14794 printk(KERN_INFO
14795 "hda_codec: Cannot set up configuration "
14796 "from BIOS. Using base mode...\n");
14797 board_config = ALC269_BASIC;
14798 }
14799 }
14800
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014801 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020014802 err = snd_hda_attach_beep_device(codec, 0x1);
14803 if (err < 0) {
14804 alc_free(codec);
14805 return err;
14806 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014807 }
14808
Kailang Yangf6a92242007-12-13 16:52:54 +010014809 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014810 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014811
Kailang Yang84898e82010-02-04 14:16:14 +010014812 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014813 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14814 * fix the sample rate of analog I/O to 44.1kHz
14815 */
14816 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14817 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014818 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014819
Takashi Iwai66946352010-03-29 17:21:45 +020014820 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020014821 alc_auto_fill_adc_caps(codec);
14822 alc_remove_invalid_adc_nids(codec);
Kailang Yang84898e82010-02-04 14:16:14 +010014823 }
14824
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014825 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014826 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014827 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010014828 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014829
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014830 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaiff818c22010-04-12 08:59:25 +020014831
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014832 spec->vmaster_nid = 0x02;
14833
Kailang Yangf6a92242007-12-13 16:52:54 +010014834 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020014835#ifdef SND_HDA_NEEDS_RESUME
14836 codec->patch_ops.resume = alc269_resume;
14837#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010014838 if (board_config == ALC269_AUTO)
14839 spec->init_hook = alc269_auto_init;
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014840 spec->shutup = alc269_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020014841
14842 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014843#ifdef CONFIG_SND_HDA_POWER_SAVE
14844 if (!spec->loopback.amplist)
14845 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014846 if (alc269_mic2_for_mute_led(codec))
14847 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014848#endif
14849
14850 return 0;
14851}
14852
14853/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014854 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14855 */
14856
14857/*
14858 * set the path ways for 2 channel output
14859 * need to set the codec line out and mic 1 pin widgets to inputs
14860 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014861static const struct hda_verb alc861_threestack_ch2_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014862 /* set pin widget 1Ah (line in) for input */
14863 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014864 /* set pin widget 18h (mic1/2) for input, for mic also enable
14865 * the vref
14866 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014867 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14868
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014869 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14870#if 0
14871 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14872 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14873#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014874 { } /* end */
14875};
14876/*
14877 * 6ch mode
14878 * need to set the codec line out and mic 1 pin widgets to outputs
14879 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014880static const struct hda_verb alc861_threestack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014881 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14882 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14883 /* set pin widget 18h (mic1) for output (CLFE)*/
14884 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14885
14886 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014887 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014888
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014889 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14890#if 0
14891 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14892 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14893#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014894 { } /* end */
14895};
14896
Takashi Iwaia9111322011-05-02 11:30:18 +020014897static const struct hda_channel_mode alc861_threestack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014898 { 2, alc861_threestack_ch2_init },
14899 { 6, alc861_threestack_ch6_init },
14900};
Takashi Iwai22309c32006-08-09 16:57:28 +020014901/* Set mic1 as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014902static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020014903 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14904 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14905 { } /* end */
14906};
14907/* Set mic1 as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014908static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020014909 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14910 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14911 { } /* end */
14912};
14913
Takashi Iwaia9111322011-05-02 11:30:18 +020014914static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020014915 { 2, alc861_uniwill_m31_ch2_init },
14916 { 4, alc861_uniwill_m31_ch4_init },
14917};
Kailang Yangdf694da2005-12-05 19:42:22 +010014918
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014919/* Set mic1 and line-in as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014920static const struct hda_verb alc861_asus_ch2_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014921 /* set pin widget 1Ah (line in) for input */
14922 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014923 /* set pin widget 18h (mic1/2) for input, for mic also enable
14924 * the vref
14925 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014926 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14927
14928 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14929#if 0
14930 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14931 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14932#endif
14933 { } /* end */
14934};
14935/* Set mic1 nad line-in as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014936static const struct hda_verb alc861_asus_ch6_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014937 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14938 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14939 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14940 /* set pin widget 18h (mic1) for output (CLFE)*/
14941 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14942 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14943 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14944 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14945
14946 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14947#if 0
14948 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14949 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14950#endif
14951 { } /* end */
14952};
14953
Takashi Iwaia9111322011-05-02 11:30:18 +020014954static const struct hda_channel_mode alc861_asus_modes[2] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014955 { 2, alc861_asus_ch2_init },
14956 { 6, alc861_asus_ch6_init },
14957};
14958
Kailang Yangdf694da2005-12-05 19:42:22 +010014959/* patch-ALC861 */
14960
Takashi Iwaia9111322011-05-02 11:30:18 +020014961static const struct snd_kcontrol_new alc861_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014962 /* output mixer control */
14963 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14964 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14965 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14966 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14967 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14968
14969 /*Input mixer control */
14970 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14971 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14972 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14973 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14974 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14975 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14976 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14977 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14978 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14979 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014980
Kailang Yangdf694da2005-12-05 19:42:22 +010014981 { } /* end */
14982};
14983
Takashi Iwaia9111322011-05-02 11:30:18 +020014984static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014985 /* output mixer control */
14986 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14987 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14988 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14989 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14990 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14991
14992 /* Input mixer control */
14993 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14994 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14995 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14996 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14997 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14998 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14999 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15000 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15001 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15002 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015003
Kailang Yangdf694da2005-12-05 19:42:22 +010015004 {
15005 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15006 .name = "Channel Mode",
15007 .info = alc_ch_mode_info,
15008 .get = alc_ch_mode_get,
15009 .put = alc_ch_mode_put,
15010 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15011 },
15012 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015013};
15014
Takashi Iwaia9111322011-05-02 11:30:18 +020015015static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015016 /* output mixer control */
15017 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15018 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15019 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015020
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015021 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015022};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015023
Takashi Iwaia9111322011-05-02 11:30:18 +020015024static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015025 /* output mixer control */
15026 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15027 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15028 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15029 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15030 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15031
15032 /* Input mixer control */
15033 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15034 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15035 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15036 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15037 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15038 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15039 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15040 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15041 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15042 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015043
Takashi Iwai22309c32006-08-09 16:57:28 +020015044 {
15045 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15046 .name = "Channel Mode",
15047 .info = alc_ch_mode_info,
15048 .get = alc_ch_mode_get,
15049 .put = alc_ch_mode_put,
15050 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15051 },
15052 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015053};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015054
Takashi Iwaia9111322011-05-02 11:30:18 +020015055static const struct snd_kcontrol_new alc861_asus_mixer[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015056 /* output mixer control */
15057 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15058 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15059 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15060 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15061 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15062
15063 /* Input mixer control */
15064 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15065 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15066 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15067 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15068 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15069 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15070 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15071 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15072 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015073 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15074
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015075 {
15076 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15077 .name = "Channel Mode",
15078 .info = alc_ch_mode_info,
15079 .get = alc_ch_mode_get,
15080 .put = alc_ch_mode_put,
15081 .private_value = ARRAY_SIZE(alc861_asus_modes),
15082 },
15083 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015084};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015085
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015086/* additional mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015087static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015088 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15089 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015090 { }
15091};
15092
Kailang Yangdf694da2005-12-05 19:42:22 +010015093/*
15094 * generic initialization of ADC, input mixers and output mixers
15095 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015096static const struct hda_verb alc861_base_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015097 /*
15098 * Unmute ADC0 and set the default input to mic-in
15099 */
15100 /* port-A for surround (rear panel) */
15101 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15102 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15103 /* port-B for mic-in (rear panel) with vref */
15104 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15105 /* port-C for line-in (rear panel) */
15106 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15107 /* port-D for Front */
15108 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15109 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15110 /* port-E for HP out (front panel) */
15111 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15112 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015113 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015114 /* port-F for mic-in (front panel) with vref */
15115 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15116 /* port-G for CLFE (rear panel) */
15117 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15118 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15119 /* port-H for side (rear panel) */
15120 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15121 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15122 /* CD-in */
15123 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15124 /* route front mic to ADC1*/
15125 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15126 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015127
Kailang Yangdf694da2005-12-05 19:42:22 +010015128 /* Unmute DAC0~3 & spdif out*/
15129 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15130 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15131 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15132 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15133 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015134
Kailang Yangdf694da2005-12-05 19:42:22 +010015135 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15136 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15137 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15138 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15139 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015140
Kailang Yangdf694da2005-12-05 19:42:22 +010015141 /* Unmute Stereo Mixer 15 */
15142 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15143 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15144 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015145 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015146
15147 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15148 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15149 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15150 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15151 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15152 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15153 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15154 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015155 /* hp used DAC 3 (Front) */
15156 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015157 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15158
15159 { }
15160};
15161
Takashi Iwaia9111322011-05-02 11:30:18 +020015162static const struct hda_verb alc861_threestack_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015163 /*
15164 * Unmute ADC0 and set the default input to mic-in
15165 */
15166 /* port-A for surround (rear panel) */
15167 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15168 /* port-B for mic-in (rear panel) with vref */
15169 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15170 /* port-C for line-in (rear panel) */
15171 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15172 /* port-D for Front */
15173 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15174 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15175 /* port-E for HP out (front panel) */
15176 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15177 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015178 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015179 /* port-F for mic-in (front panel) with vref */
15180 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15181 /* port-G for CLFE (rear panel) */
15182 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15183 /* port-H for side (rear panel) */
15184 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15185 /* CD-in */
15186 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15187 /* route front mic to ADC1*/
15188 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15189 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15190 /* Unmute DAC0~3 & spdif out*/
15191 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15192 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15193 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15194 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015196
Kailang Yangdf694da2005-12-05 19:42:22 +010015197 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15198 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15199 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15200 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15201 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015202
Kailang Yangdf694da2005-12-05 19:42:22 +010015203 /* Unmute Stereo Mixer 15 */
15204 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15205 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15206 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015207 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015208
15209 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15210 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15211 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15212 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15213 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15214 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15215 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15216 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015217 /* hp used DAC 3 (Front) */
15218 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015219 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15220 { }
15221};
Takashi Iwai22309c32006-08-09 16:57:28 +020015222
Takashi Iwaia9111322011-05-02 11:30:18 +020015223static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015224 /*
15225 * Unmute ADC0 and set the default input to mic-in
15226 */
15227 /* port-A for surround (rear panel) */
15228 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15229 /* port-B for mic-in (rear panel) with vref */
15230 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15231 /* port-C for line-in (rear panel) */
15232 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15233 /* port-D for Front */
15234 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15235 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15236 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015237 /* this has to be set to VREF80 */
15238 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015239 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015240 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015241 /* port-F for mic-in (front panel) with vref */
15242 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15243 /* port-G for CLFE (rear panel) */
15244 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15245 /* port-H for side (rear panel) */
15246 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15247 /* CD-in */
15248 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15249 /* route front mic to ADC1*/
15250 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15251 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15252 /* Unmute DAC0~3 & spdif out*/
15253 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15254 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15255 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15256 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15257 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015258
Takashi Iwai22309c32006-08-09 16:57:28 +020015259 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15260 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15261 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15262 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15263 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015264
Takashi Iwai22309c32006-08-09 16:57:28 +020015265 /* Unmute Stereo Mixer 15 */
15266 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15267 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15268 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015269 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015270
15271 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15272 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15273 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15274 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15275 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15276 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15277 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15278 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015279 /* hp used DAC 3 (Front) */
15280 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015281 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15282 { }
15283};
15284
Takashi Iwaia9111322011-05-02 11:30:18 +020015285static const struct hda_verb alc861_asus_init_verbs[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015286 /*
15287 * Unmute ADC0 and set the default input to mic-in
15288 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015289 /* port-A for surround (rear panel)
15290 * according to codec#0 this is the HP jack
15291 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015292 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15293 /* route front PCM to HP */
15294 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15295 /* port-B for mic-in (rear panel) with vref */
15296 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15297 /* port-C for line-in (rear panel) */
15298 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15299 /* port-D for Front */
15300 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15301 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15302 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015303 /* this has to be set to VREF80 */
15304 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015305 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015306 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015307 /* port-F for mic-in (front panel) with vref */
15308 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15309 /* port-G for CLFE (rear panel) */
15310 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15311 /* port-H for side (rear panel) */
15312 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15313 /* CD-in */
15314 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15315 /* route front mic to ADC1*/
15316 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15317 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15318 /* Unmute DAC0~3 & spdif out*/
15319 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15320 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15321 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15322 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15323 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15324 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15325 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15326 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15327 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15328 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015329
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015330 /* Unmute Stereo Mixer 15 */
15331 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15332 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15333 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015334 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015335
15336 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15337 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15338 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15339 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15340 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15341 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15342 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15343 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015344 /* hp used DAC 3 (Front) */
15345 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015346 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15347 { }
15348};
15349
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015350/* additional init verbs for ASUS laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020015351static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015352 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15353 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15354 { }
15355};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015356
Takashi Iwaia9111322011-05-02 11:30:18 +020015357static const struct hda_verb alc861_toshiba_init_verbs[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015358 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015359
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015360 { }
15361};
15362
15363/* toggle speaker-output according to the hp-jack state */
15364static void alc861_toshiba_automute(struct hda_codec *codec)
15365{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015366 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015367
Takashi Iwai47fd8302007-08-10 17:11:07 +020015368 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15369 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15370 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15371 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015372}
15373
15374static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15375 unsigned int res)
15376{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015377 if ((res >> 26) == ALC880_HP_EVENT)
15378 alc861_toshiba_automute(codec);
15379}
15380
Kailang Yangdf694da2005-12-05 19:42:22 +010015381#define ALC861_DIGOUT_NID 0x07
15382
Takashi Iwaia9111322011-05-02 11:30:18 +020015383static const struct hda_channel_mode alc861_8ch_modes[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015384 { 8, NULL }
15385};
15386
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015387static const hda_nid_t alc861_dac_nids[4] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015388 /* front, surround, clfe, side */
15389 0x03, 0x06, 0x05, 0x04
15390};
15391
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015392static const hda_nid_t alc660_dac_nids[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015393 /* front, clfe, surround */
15394 0x03, 0x05, 0x06
15395};
15396
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015397static const hda_nid_t alc861_adc_nids[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015398 /* ADC0-2 */
15399 0x08,
15400};
15401
Takashi Iwaia9111322011-05-02 11:30:18 +020015402static const struct hda_input_mux alc861_capture_source = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015403 .num_items = 5,
15404 .items = {
15405 { "Mic", 0x0 },
15406 { "Front Mic", 0x3 },
15407 { "Line", 0x1 },
15408 { "CD", 0x4 },
15409 { "Mixer", 0x5 },
15410 },
15411};
15412
Takashi Iwai1c209302009-07-22 15:17:45 +020015413static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15414{
15415 struct alc_spec *spec = codec->spec;
15416 hda_nid_t mix, srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +020015417 int i, num;
Takashi Iwai1c209302009-07-22 15:17:45 +020015418
15419 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15420 return 0;
15421 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15422 if (num < 0)
15423 return 0;
15424 for (i = 0; i < num; i++) {
15425 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015426 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015427 if (type != AC_WID_AUD_OUT)
15428 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020015429 if (!found_in_nid_list(srcs[i], spec->multiout.dac_nids,
15430 spec->multiout.num_dacs))
Takashi Iwai1c209302009-07-22 15:17:45 +020015431 return srcs[i];
15432 }
15433 return 0;
15434}
15435
Kailang Yangdf694da2005-12-05 19:42:22 +010015436/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaicb053a82011-06-27 11:32:07 +020015437static int alc861_auto_fill_dac_nids(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015438{
Takashi Iwai1c209302009-07-22 15:17:45 +020015439 struct alc_spec *spec = codec->spec;
Takashi Iwaicb053a82011-06-27 11:32:07 +020015440 const struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010015441 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015442 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015443
15444 spec->multiout.dac_nids = spec->private_dac_nids;
15445 for (i = 0; i < cfg->line_outs; i++) {
15446 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015447 dac = alc861_look_for_dac(codec, nid);
15448 if (!dac)
15449 continue;
Takashi Iwaidda14412011-05-02 11:29:30 +020015450 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015451 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015452 return 0;
15453}
15454
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015455static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15456 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015457{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015458 return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015459 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15460}
15461
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015462#define alc861_create_out_sw(codec, pfx, nid, chs) \
15463 __alc861_create_out_sw(codec, pfx, nid, 0, chs)
15464
Takashi Iwai1c209302009-07-22 15:17:45 +020015465/* add playback controls from the parsed DAC table */
15466static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15467 const struct auto_pin_cfg *cfg)
15468{
15469 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015470 hda_nid_t nid;
Takashi Iwaice764ab2011-04-27 16:35:23 +020015471 int i, err, noutputs;
Takashi Iwai1c209302009-07-22 15:17:45 +020015472
Takashi Iwaice764ab2011-04-27 16:35:23 +020015473 noutputs = cfg->line_outs;
15474 if (spec->multi_ios > 0)
15475 noutputs += spec->multi_ios;
15476
15477 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020015478 const char *name;
15479 int index;
Kailang Yangdf694da2005-12-05 19:42:22 +010015480 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015481 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015482 continue;
Takashi Iwai6843ca12011-06-24 11:03:58 +020015483 name = alc_get_line_out_pfx(spec, i, true, &index);
15484 if (!name) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015485 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015486 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015487 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015488 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015489 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015490 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015491 return err;
15492 } else {
David Henningsson5a882642011-03-23 08:35:07 +010015493 err = __alc861_create_out_sw(codec, name, nid, index, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015494 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015495 return err;
15496 }
15497 }
15498 return 0;
15499}
15500
Takashi Iwai1c209302009-07-22 15:17:45 +020015501static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015502{
Takashi Iwai1c209302009-07-22 15:17:45 +020015503 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015504 int err;
15505 hda_nid_t nid;
15506
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015507 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015508 return 0;
15509
15510 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015511 nid = alc861_look_for_dac(codec, pin);
15512 if (nid) {
15513 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15514 if (err < 0)
15515 return err;
15516 spec->multiout.hp_nid = nid;
15517 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015518 }
15519 return 0;
15520}
15521
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015522static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15523 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015524 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015525{
Takashi Iwai1c209302009-07-22 15:17:45 +020015526 hda_nid_t mix, srcs[5];
15527 int i, num;
15528
Jacek Luczak564c5be2008-05-03 18:41:23 +020015529 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15530 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015531 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015532 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015533 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15534 return;
15535 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15536 if (num < 0)
15537 return;
15538 for (i = 0; i < num; i++) {
15539 unsigned int mute;
15540 if (srcs[i] == dac || srcs[i] == 0x15)
15541 mute = AMP_IN_UNMUTE(i);
15542 else
15543 mute = AMP_IN_MUTE(i);
15544 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15545 mute);
15546 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015547}
15548
15549static void alc861_auto_init_multi_out(struct hda_codec *codec)
15550{
15551 struct alc_spec *spec = codec->spec;
15552 int i;
15553
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020015554 for (i = 0; i < spec->autocfg.line_outs + spec->multi_ios; i++) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015555 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015556 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015557 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015558 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015559 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015560 }
15561}
15562
15563static void alc861_auto_init_hp_out(struct hda_codec *codec)
15564{
15565 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015566
Takashi Iwai15870f02009-10-05 08:25:13 +020015567 if (spec->autocfg.hp_outs)
15568 alc861_auto_set_output_and_unmute(codec,
15569 spec->autocfg.hp_pins[0],
15570 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015571 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015572 if (spec->autocfg.speaker_outs)
15573 alc861_auto_set_output_and_unmute(codec,
15574 spec->autocfg.speaker_pins[0],
15575 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015576 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015577}
15578
Kailang Yangdf694da2005-12-05 19:42:22 +010015579/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015580/* return 1 if successful, 0 if the proper config is not found,
15581 * or a negative error code
15582 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015583static int alc861_parse_auto_config(struct hda_codec *codec)
15584{
15585 struct alc_spec *spec = codec->spec;
15586 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015587 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015588
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015589 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15590 alc861_ignore);
15591 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015592 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015593 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015594 return 0; /* can't find valid BIOS pin config */
15595
Takashi Iwaicb053a82011-06-27 11:32:07 +020015596 err = alc861_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015597 if (err < 0)
15598 return err;
Takashi Iwaicb053a82011-06-27 11:32:07 +020015599 err = alc_auto_add_multi_channel_mode(codec, alc861_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020015600 if (err < 0)
15601 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015602 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015603 if (err < 0)
15604 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015605 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015606 if (err < 0)
15607 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020015608 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015609 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015610 return err;
15611
15612 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15613
Takashi Iwai757899a2010-07-30 10:48:14 +020015614 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015615
Takashi Iwai603c4012008-07-30 15:01:44 +020015616 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015617 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015618
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015619 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015620 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015621
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020015622 if (!spec->dual_adc_switch)
15623 alc_remove_invalid_adc_nids(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015624
Kailang Yang6227cdc2010-02-25 08:36:52 +010015625 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015626
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020015627 set_capture_mixer(codec);
15628
Kailang Yangdf694da2005-12-05 19:42:22 +010015629 return 1;
15630}
15631
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015632/* additional initialization for auto-configuration model */
15633static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015634{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015635 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015636 alc861_auto_init_multi_out(codec);
15637 alc861_auto_init_hp_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020015638 alc_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015639 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015640 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015641 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015642}
15643
Takashi Iwaicb53c622007-08-10 17:21:45 +020015644#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +020015645static const struct hda_amp_list alc861_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +020015646 { 0x15, HDA_INPUT, 0 },
15647 { 0x15, HDA_INPUT, 1 },
15648 { 0x15, HDA_INPUT, 2 },
15649 { 0x15, HDA_INPUT, 3 },
15650 { } /* end */
15651};
15652#endif
15653
Kailang Yangdf694da2005-12-05 19:42:22 +010015654
15655/*
15656 * configuration and preset
15657 */
Takashi Iwaiea734962011-01-17 11:29:34 +010015658static const char * const alc861_models[ALC861_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015659 [ALC861_3ST] = "3stack",
15660 [ALC660_3ST] = "3stack-660",
15661 [ALC861_3ST_DIG] = "3stack-dig",
15662 [ALC861_6ST_DIG] = "6stack-dig",
15663 [ALC861_UNIWILL_M31] = "uniwill-m31",
15664 [ALC861_TOSHIBA] = "toshiba",
15665 [ALC861_ASUS] = "asus",
15666 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15667 [ALC861_AUTO] = "auto",
15668};
15669
Takashi Iwaia9111322011-05-02 11:30:18 +020015670static const struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015671 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015672 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15673 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15674 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015675 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015676 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015677 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015678 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15679 * Any other models that need this preset?
15680 */
15681 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015682 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15683 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015684 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15685 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15686 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15687 /* FIXME: the below seems conflict */
15688 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15689 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15690 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015691 {}
15692};
15693
Takashi Iwaia9111322011-05-02 11:30:18 +020015694static const struct alc_config_preset alc861_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015695 [ALC861_3ST] = {
15696 .mixers = { alc861_3ST_mixer },
15697 .init_verbs = { alc861_threestack_init_verbs },
15698 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15699 .dac_nids = alc861_dac_nids,
15700 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15701 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015702 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015703 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15704 .adc_nids = alc861_adc_nids,
15705 .input_mux = &alc861_capture_source,
15706 },
15707 [ALC861_3ST_DIG] = {
15708 .mixers = { alc861_base_mixer },
15709 .init_verbs = { alc861_threestack_init_verbs },
15710 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15711 .dac_nids = alc861_dac_nids,
15712 .dig_out_nid = ALC861_DIGOUT_NID,
15713 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15714 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015715 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015716 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15717 .adc_nids = alc861_adc_nids,
15718 .input_mux = &alc861_capture_source,
15719 },
15720 [ALC861_6ST_DIG] = {
15721 .mixers = { alc861_base_mixer },
15722 .init_verbs = { alc861_base_init_verbs },
15723 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15724 .dac_nids = alc861_dac_nids,
15725 .dig_out_nid = ALC861_DIGOUT_NID,
15726 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15727 .channel_mode = alc861_8ch_modes,
15728 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15729 .adc_nids = alc861_adc_nids,
15730 .input_mux = &alc861_capture_source,
15731 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015732 [ALC660_3ST] = {
15733 .mixers = { alc861_3ST_mixer },
15734 .init_verbs = { alc861_threestack_init_verbs },
15735 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15736 .dac_nids = alc660_dac_nids,
15737 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15738 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015739 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015740 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15741 .adc_nids = alc861_adc_nids,
15742 .input_mux = &alc861_capture_source,
15743 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015744 [ALC861_UNIWILL_M31] = {
15745 .mixers = { alc861_uniwill_m31_mixer },
15746 .init_verbs = { alc861_uniwill_m31_init_verbs },
15747 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15748 .dac_nids = alc861_dac_nids,
15749 .dig_out_nid = ALC861_DIGOUT_NID,
15750 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15751 .channel_mode = alc861_uniwill_m31_modes,
15752 .need_dac_fix = 1,
15753 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15754 .adc_nids = alc861_adc_nids,
15755 .input_mux = &alc861_capture_source,
15756 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015757 [ALC861_TOSHIBA] = {
15758 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015759 .init_verbs = { alc861_base_init_verbs,
15760 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015761 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15762 .dac_nids = alc861_dac_nids,
15763 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15764 .channel_mode = alc883_3ST_2ch_modes,
15765 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15766 .adc_nids = alc861_adc_nids,
15767 .input_mux = &alc861_capture_source,
15768 .unsol_event = alc861_toshiba_unsol_event,
15769 .init_hook = alc861_toshiba_automute,
15770 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015771 [ALC861_ASUS] = {
15772 .mixers = { alc861_asus_mixer },
15773 .init_verbs = { alc861_asus_init_verbs },
15774 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15775 .dac_nids = alc861_dac_nids,
15776 .dig_out_nid = ALC861_DIGOUT_NID,
15777 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15778 .channel_mode = alc861_asus_modes,
15779 .need_dac_fix = 1,
15780 .hp_nid = 0x06,
15781 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15782 .adc_nids = alc861_adc_nids,
15783 .input_mux = &alc861_capture_source,
15784 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015785 [ALC861_ASUS_LAPTOP] = {
15786 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15787 .init_verbs = { alc861_asus_init_verbs,
15788 alc861_asus_laptop_init_verbs },
15789 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15790 .dac_nids = alc861_dac_nids,
15791 .dig_out_nid = ALC861_DIGOUT_NID,
15792 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15793 .channel_mode = alc883_3ST_2ch_modes,
15794 .need_dac_fix = 1,
15795 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15796 .adc_nids = alc861_adc_nids,
15797 .input_mux = &alc861_capture_source,
15798 },
15799};
Kailang Yangdf694da2005-12-05 19:42:22 +010015800
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015801/* Pin config fixes */
15802enum {
15803 PINFIX_FSC_AMILO_PI1505,
15804};
15805
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015806static const struct alc_fixup alc861_fixups[] = {
15807 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015808 .type = ALC_FIXUP_PINS,
15809 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020015810 { 0x0b, 0x0221101f }, /* HP */
15811 { 0x0f, 0x90170310 }, /* speaker */
15812 { }
15813 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015814 },
15815};
15816
Takashi Iwaia9111322011-05-02 11:30:18 +020015817static const struct snd_pci_quirk alc861_fixup_tbl[] = {
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015818 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15819 {}
15820};
Kailang Yangdf694da2005-12-05 19:42:22 +010015821
15822static int patch_alc861(struct hda_codec *codec)
15823{
15824 struct alc_spec *spec;
15825 int board_config;
15826 int err;
15827
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015828 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015829 if (spec == NULL)
15830 return -ENOMEM;
15831
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015832 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015833
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020015834 spec->mixer_nid = 0x15;
15835
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015836 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15837 alc861_models,
15838 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015839
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015840 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015841 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15842 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015843 board_config = ALC861_AUTO;
15844 }
15845
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015846 if (board_config == ALC861_AUTO) {
15847 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
15848 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
15849 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015850
Kailang Yangdf694da2005-12-05 19:42:22 +010015851 if (board_config == ALC861_AUTO) {
15852 /* automatic parse from the BIOS config */
15853 err = alc861_parse_auto_config(codec);
15854 if (err < 0) {
15855 alc_free(codec);
15856 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015857 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015858 printk(KERN_INFO
15859 "hda_codec: Cannot set up configuration "
15860 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015861 board_config = ALC861_3ST_DIG;
15862 }
15863 }
15864
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015865 err = snd_hda_attach_beep_device(codec, 0x23);
15866 if (err < 0) {
15867 alc_free(codec);
15868 return err;
15869 }
15870
Kailang Yangdf694da2005-12-05 19:42:22 +010015871 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015872 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015873
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015874 if (!spec->cap_mixer)
15875 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015876 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15877
Takashi Iwai2134ea42008-01-10 16:53:55 +010015878 spec->vmaster_nid = 0x03;
15879
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015880 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015881
Kailang Yangdf694da2005-12-05 19:42:22 +010015882 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015883 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015884 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015885#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015886 spec->power_hook = alc_power_eapd;
15887#endif
15888 }
15889#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015890 if (!spec->loopback.amplist)
15891 spec->loopback.amplist = alc861_loopbacks;
15892#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015893
Kailang Yangdf694da2005-12-05 19:42:22 +010015894 return 0;
15895}
15896
15897/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015898 * ALC861-VD support
15899 *
15900 * Based on ALC882
15901 *
15902 * In addition, an independent DAC
15903 */
15904#define ALC861VD_DIGOUT_NID 0x06
15905
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015906static const hda_nid_t alc861vd_dac_nids[4] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015907 /* front, surr, clfe, side surr */
15908 0x02, 0x03, 0x04, 0x05
15909};
15910
15911/* dac_nids for ALC660vd are in a different order - according to
15912 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015913 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015914 * of ALC660vd codecs, but for now there is only 3stack mixer
15915 * - and it is the same as in 861vd.
15916 * adc_nids in ALC660vd are (is) the same as in 861vd
15917 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015918static const hda_nid_t alc660vd_dac_nids[3] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015919 /* front, rear, clfe, rear_surr */
15920 0x02, 0x04, 0x03
15921};
15922
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015923static const hda_nid_t alc861vd_adc_nids[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015924 /* ADC0 */
15925 0x09,
15926};
15927
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015928static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010015929
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015930/* input MUX */
15931/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020015932static const struct hda_input_mux alc861vd_capture_source = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015933 .num_items = 4,
15934 .items = {
15935 { "Mic", 0x0 },
15936 { "Front Mic", 0x1 },
15937 { "Line", 0x2 },
15938 { "CD", 0x4 },
15939 },
15940};
15941
Takashi Iwaia9111322011-05-02 11:30:18 +020015942static const struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015943 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015944 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010015945 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010015946 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015947 },
15948};
15949
Takashi Iwaia9111322011-05-02 11:30:18 +020015950static const struct hda_input_mux alc861vd_hp_capture_source = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020015951 .num_items = 2,
15952 .items = {
15953 { "Front Mic", 0x0 },
15954 { "ATAPI Mic", 0x1 },
15955 },
15956};
15957
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015958/*
15959 * 2ch mode
15960 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015961static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015962 { 2, NULL }
15963};
15964
15965/*
15966 * 6ch mode
15967 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015968static const struct hda_verb alc861vd_6stack_ch6_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015969 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15970 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15971 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15972 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15973 { } /* end */
15974};
15975
15976/*
15977 * 8ch mode
15978 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015979static const struct hda_verb alc861vd_6stack_ch8_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015980 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15981 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15982 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15983 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15984 { } /* end */
15985};
15986
Takashi Iwaia9111322011-05-02 11:30:18 +020015987static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015988 { 6, alc861vd_6stack_ch6_init },
15989 { 8, alc861vd_6stack_ch8_init },
15990};
15991
Takashi Iwaia9111322011-05-02 11:30:18 +020015992static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015993 {
15994 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15995 .name = "Channel Mode",
15996 .info = alc_ch_mode_info,
15997 .get = alc_ch_mode_get,
15998 .put = alc_ch_mode_put,
15999 },
16000 { } /* end */
16001};
16002
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016003/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16004 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16005 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016006static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016007 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16008 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16009
16010 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16011 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16012
16013 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16014 HDA_OUTPUT),
16015 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16016 HDA_OUTPUT),
16017 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16018 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16019
16020 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16021 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16022
16023 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16024
David Henningsson5f99f862011-01-04 15:24:24 +010016025 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016026 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16027 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16028
David Henningsson5f99f862011-01-04 15:24:24 +010016029 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016030 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16031 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16032
16033 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16034 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16035
16036 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16037 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16038
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016039 { } /* end */
16040};
16041
Takashi Iwaia9111322011-05-02 11:30:18 +020016042static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016043 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16044 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16045
16046 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16047
David Henningsson5f99f862011-01-04 15:24:24 +010016048 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016049 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16050 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16051
David Henningsson5f99f862011-01-04 15:24:24 +010016052 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016053 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16054 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16055
16056 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16057 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16058
16059 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16060 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16061
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016062 { } /* end */
16063};
16064
Takashi Iwaia9111322011-05-02 11:30:18 +020016065static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016066 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16067 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16068 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16069
16070 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16071
David Henningsson5f99f862011-01-04 15:24:24 +010016072 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016073 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16074 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16075
David Henningsson5f99f862011-01-04 15:24:24 +010016076 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016077 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16078 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16079
16080 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16081 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16082
16083 { } /* end */
16084};
16085
Tobin Davisb419f342008-03-07 11:57:51 +010016086/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016087 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016088 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016089static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016090 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16091 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016092 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16093 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016094 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016095 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16096 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016097 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016098 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16099 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016100 { } /* end */
16101};
16102
Kailang Yangd1a991a2007-08-15 16:21:59 +020016103/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16104 * Front Mic=0x18, ATAPI Mic = 0x19,
16105 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016106static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016107 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16108 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16109 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16110 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16111 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16112 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16113 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16114 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016115
Kailang Yangd1a991a2007-08-15 16:21:59 +020016116 { } /* end */
16117};
16118
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016119/*
16120 * generic initialization of ADC, input mixers and output mixers
16121 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016122static const struct hda_verb alc861vd_volume_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016123 /*
16124 * Unmute ADC0 and set the default input to mic-in
16125 */
16126 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16127 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16128
16129 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16130 * the analog-loopback mixer widget
16131 */
16132 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016133 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16134 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16135 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16136 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16137 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016138
16139 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016140 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16141 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16142 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016143 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016144
16145 /*
16146 * Set up output mixers (0x02 - 0x05)
16147 */
16148 /* set vol=0 to output mixers */
16149 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16150 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16151 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16152 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16153
16154 /* set up input amps for analog loopback */
16155 /* Amp Indices: DAC = 0, mixer = 1 */
16156 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16157 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16158 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16159 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16160 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16161 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16162 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16163 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16164
16165 { }
16166};
16167
16168/*
16169 * 3-stack pin configuration:
16170 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16171 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016172static const struct hda_verb alc861vd_3stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016173 /*
16174 * Set pin mode and muting
16175 */
16176 /* set front pin widgets 0x14 for output */
16177 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16178 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16179 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16180
16181 /* Mic (rear) pin: input vref at 80% */
16182 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16183 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16184 /* Front Mic pin: input vref at 80% */
16185 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16186 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16187 /* Line In pin: input */
16188 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16189 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16190 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16191 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16192 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16193 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16194 /* CD pin widget for input */
16195 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16196
16197 { }
16198};
16199
16200/*
16201 * 6-stack pin configuration:
16202 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016203static const struct hda_verb alc861vd_6stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016204 /*
16205 * Set pin mode and muting
16206 */
16207 /* set front pin widgets 0x14 for output */
16208 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16209 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16210 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16211
16212 /* Rear Pin: output 1 (0x0d) */
16213 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16214 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16215 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16216 /* CLFE Pin: output 2 (0x0e) */
16217 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16218 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16219 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16220 /* Side Pin: output 3 (0x0f) */
16221 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16222 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16223 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16224
16225 /* Mic (rear) pin: input vref at 80% */
16226 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16227 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16228 /* Front Mic pin: input vref at 80% */
16229 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16230 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16231 /* Line In pin: input */
16232 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16233 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16234 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16235 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16236 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16237 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16238 /* CD pin widget for input */
16239 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16240
16241 { }
16242};
16243
Takashi Iwaia9111322011-05-02 11:30:18 +020016244static const struct hda_verb alc861vd_eapd_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016245 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16246 { }
16247};
16248
Takashi Iwaia9111322011-05-02 11:30:18 +020016249static const struct hda_verb alc660vd_eapd_verbs[] = {
Kailang Yangf9423e72008-05-27 12:32:25 +020016250 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16251 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16252 { }
16253};
16254
Takashi Iwaia9111322011-05-02 11:30:18 +020016255static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016256 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16257 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16258 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16259 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016260 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016261 {}
16262};
16263
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016264static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016265{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016266 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016267 spec->autocfg.hp_pins[0] = 0x1b;
16268 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016269 spec->automute = 1;
16270 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016271}
16272
16273static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16274{
Takashi Iwaid922b512011-04-28 12:18:53 +020016275 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016276 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016277}
16278
16279static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16280 unsigned int res)
16281{
16282 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016283 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016284 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016285 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016286 default:
Takashi Iwaid922b512011-04-28 12:18:53 +020016287 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016288 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016289 }
16290}
16291
Takashi Iwaia9111322011-05-02 11:30:18 +020016292static const struct hda_verb alc861vd_dallas_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020016293 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16294 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16295 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16296 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16297
16298 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16299 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16300 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16301 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16302 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16303 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16304 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16305 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016306
Kailang Yang272a5272007-05-14 11:00:38 +020016307 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16308 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16309 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16310 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16311 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16312 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16313 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16314 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16315
16316 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16317 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16318 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16319 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16320 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16321 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16322 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16323 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16324
16325 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16326 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16327 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16328 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16329
16330 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016331 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016332 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16333
16334 { } /* end */
16335};
16336
16337/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016338static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016339{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016340 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016341
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016342 spec->autocfg.hp_pins[0] = 0x15;
16343 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016344 spec->automute = 1;
16345 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +020016346}
16347
Takashi Iwaicb53c622007-08-10 17:21:45 +020016348#ifdef CONFIG_SND_HDA_POWER_SAVE
16349#define alc861vd_loopbacks alc880_loopbacks
16350#endif
16351
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016352/*
16353 * configuration and preset
16354 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016355static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016356 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016357 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016358 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016359 [ALC861VD_3ST] = "3stack",
16360 [ALC861VD_3ST_DIG] = "3stack-digout",
16361 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016362 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016363 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016364 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016365 [ALC861VD_AUTO] = "auto",
16366};
16367
Takashi Iwaia9111322011-05-02 11:30:18 +020016368static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016369 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16370 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016371 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016372 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016373 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016374 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016375 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016376 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016377 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016378 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016379 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016380 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016381 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016382 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016383 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016384 {}
16385};
16386
Takashi Iwaia9111322011-05-02 11:30:18 +020016387static const struct alc_config_preset alc861vd_presets[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016388 [ALC660VD_3ST] = {
16389 .mixers = { alc861vd_3st_mixer },
16390 .init_verbs = { alc861vd_volume_init_verbs,
16391 alc861vd_3stack_init_verbs },
16392 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16393 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016394 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16395 .channel_mode = alc861vd_3stack_2ch_modes,
16396 .input_mux = &alc861vd_capture_source,
16397 },
Mike Crash6963f842007-06-25 12:12:51 +020016398 [ALC660VD_3ST_DIG] = {
16399 .mixers = { alc861vd_3st_mixer },
16400 .init_verbs = { alc861vd_volume_init_verbs,
16401 alc861vd_3stack_init_verbs },
16402 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16403 .dac_nids = alc660vd_dac_nids,
16404 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016405 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16406 .channel_mode = alc861vd_3stack_2ch_modes,
16407 .input_mux = &alc861vd_capture_source,
16408 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016409 [ALC861VD_3ST] = {
16410 .mixers = { alc861vd_3st_mixer },
16411 .init_verbs = { alc861vd_volume_init_verbs,
16412 alc861vd_3stack_init_verbs },
16413 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16414 .dac_nids = alc861vd_dac_nids,
16415 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16416 .channel_mode = alc861vd_3stack_2ch_modes,
16417 .input_mux = &alc861vd_capture_source,
16418 },
16419 [ALC861VD_3ST_DIG] = {
16420 .mixers = { alc861vd_3st_mixer },
16421 .init_verbs = { alc861vd_volume_init_verbs,
16422 alc861vd_3stack_init_verbs },
16423 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16424 .dac_nids = alc861vd_dac_nids,
16425 .dig_out_nid = ALC861VD_DIGOUT_NID,
16426 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16427 .channel_mode = alc861vd_3stack_2ch_modes,
16428 .input_mux = &alc861vd_capture_source,
16429 },
16430 [ALC861VD_6ST_DIG] = {
16431 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16432 .init_verbs = { alc861vd_volume_init_verbs,
16433 alc861vd_6stack_init_verbs },
16434 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16435 .dac_nids = alc861vd_dac_nids,
16436 .dig_out_nid = ALC861VD_DIGOUT_NID,
16437 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16438 .channel_mode = alc861vd_6stack_modes,
16439 .input_mux = &alc861vd_capture_source,
16440 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016441 [ALC861VD_LENOVO] = {
16442 .mixers = { alc861vd_lenovo_mixer },
16443 .init_verbs = { alc861vd_volume_init_verbs,
16444 alc861vd_3stack_init_verbs,
16445 alc861vd_eapd_verbs,
16446 alc861vd_lenovo_unsol_verbs },
16447 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16448 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016449 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16450 .channel_mode = alc861vd_3stack_2ch_modes,
16451 .input_mux = &alc861vd_capture_source,
16452 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016453 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016454 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016455 },
Kailang Yang272a5272007-05-14 11:00:38 +020016456 [ALC861VD_DALLAS] = {
16457 .mixers = { alc861vd_dallas_mixer },
16458 .init_verbs = { alc861vd_dallas_verbs },
16459 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16460 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016461 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16462 .channel_mode = alc861vd_3stack_2ch_modes,
16463 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020016464 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016465 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020016466 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016467 },
16468 [ALC861VD_HP] = {
16469 .mixers = { alc861vd_hp_mixer },
16470 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16471 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16472 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016473 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016474 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16475 .channel_mode = alc861vd_3stack_2ch_modes,
16476 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020016477 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016478 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020016479 .init_hook = alc_hp_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020016480 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016481 [ALC660VD_ASUS_V1S] = {
16482 .mixers = { alc861vd_lenovo_mixer },
16483 .init_verbs = { alc861vd_volume_init_verbs,
16484 alc861vd_3stack_init_verbs,
16485 alc861vd_eapd_verbs,
16486 alc861vd_lenovo_unsol_verbs },
16487 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16488 .dac_nids = alc660vd_dac_nids,
16489 .dig_out_nid = ALC861VD_DIGOUT_NID,
16490 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16491 .channel_mode = alc861vd_3stack_2ch_modes,
16492 .input_mux = &alc861vd_capture_source,
16493 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016494 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016495 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016496 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016497};
16498
16499/*
16500 * BIOS auto configuration
16501 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016502#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16503#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16504
16505/* add playback controls from the parsed DAC table */
Takashi Iwai569ed342011-01-19 10:14:46 +010016506/* Based on ALC880 version. But ALC861VD has separate,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016507 * different NIDs for mute/unmute switch and volume control */
16508static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16509 const struct auto_pin_cfg *cfg)
16510{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016511 hda_nid_t nid_v, nid_s;
Takashi Iwaice764ab2011-04-27 16:35:23 +020016512 int i, err, noutputs;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016513
Takashi Iwaice764ab2011-04-27 16:35:23 +020016514 noutputs = cfg->line_outs;
16515 if (spec->multi_ios > 0)
16516 noutputs += spec->multi_ios;
16517
16518 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020016519 const char *name;
16520 int index;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016521 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016522 continue;
16523 nid_v = alc861vd_idx_to_mixer_vol(
16524 alc880_dac_to_idx(
16525 spec->multiout.dac_nids[i]));
16526 nid_s = alc861vd_idx_to_mixer_switch(
16527 alc880_dac_to_idx(
16528 spec->multiout.dac_nids[i]));
16529
Takashi Iwai6843ca12011-06-24 11:03:58 +020016530 name = alc_get_line_out_pfx(spec, i, true, &index);
16531 if (!name) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016532 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016533 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16534 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016535 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16536 HDA_OUTPUT));
16537 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016538 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016539 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16540 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016541 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16542 HDA_OUTPUT));
16543 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016544 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016545 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16546 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016547 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16548 HDA_INPUT));
16549 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016550 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016551 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16552 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016553 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16554 HDA_INPUT));
16555 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016556 return err;
16557 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016558 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
David Henningsson5a882642011-03-23 08:35:07 +010016559 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016560 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16561 HDA_OUTPUT));
16562 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016563 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016564 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
David Henningsson5a882642011-03-23 08:35:07 +010016565 name, index,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016566 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016567 HDA_INPUT));
16568 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016569 return err;
16570 }
16571 }
16572 return 0;
16573}
16574
16575/* add playback controls for speaker and HP outputs */
16576/* Based on ALC880 version. But ALC861VD has separate,
16577 * different NIDs for mute/unmute switch and volume control */
16578static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16579 hda_nid_t pin, const char *pfx)
16580{
16581 hda_nid_t nid_v, nid_s;
16582 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016583
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016584 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016585 return 0;
16586
16587 if (alc880_is_fixed_pin(pin)) {
16588 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16589 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016590 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016591 spec->multiout.hp_nid = nid_v;
16592 else
16593 spec->multiout.extra_out_nid[0] = nid_v;
16594 /* control HP volume/switch on the output mixer amp */
16595 nid_v = alc861vd_idx_to_mixer_vol(
16596 alc880_fixed_pin_idx(pin));
16597 nid_s = alc861vd_idx_to_mixer_switch(
16598 alc880_fixed_pin_idx(pin));
16599
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016600 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016601 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16602 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016603 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016604 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016605 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16606 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016607 return err;
16608 } else if (alc880_is_multi_pin(pin)) {
16609 /* set manual connection */
16610 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016611 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016612 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16613 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016614 return err;
16615 }
16616 return 0;
16617}
16618
16619/* parse the BIOS configuration and set up the alc_spec
16620 * return 1 if successful, 0 if the proper config is not found,
16621 * or a negative error code
16622 * Based on ALC880 version - had to change it to override
16623 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16624static int alc861vd_parse_auto_config(struct hda_codec *codec)
16625{
16626 struct alc_spec *spec = codec->spec;
16627 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016628 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016629
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016630 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16631 alc861vd_ignore);
16632 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016633 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016634 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016635 return 0; /* can't find valid BIOS pin config */
16636
Takashi Iwai343a04b2011-07-06 14:28:39 +020016637 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016638 if (err < 0)
16639 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020016640 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020016641 if (err < 0)
16642 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016643 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16644 if (err < 0)
16645 return err;
16646 err = alc861vd_auto_create_extra_out(spec,
16647 spec->autocfg.speaker_pins[0],
16648 "Speaker");
16649 if (err < 0)
16650 return err;
16651 err = alc861vd_auto_create_extra_out(spec,
16652 spec->autocfg.hp_pins[0],
16653 "Headphone");
16654 if (err < 0)
16655 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020016656 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016657 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016658 return err;
16659
16660 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16661
Takashi Iwai757899a2010-07-30 10:48:14 +020016662 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016663
Takashi Iwai603c4012008-07-30 15:01:44 +020016664 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016665 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016666
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016667 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016668 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016669
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020016670 if (!spec->dual_adc_switch)
16671 alc_remove_invalid_adc_nids(codec);
16672
Takashi Iwai776e1842007-08-29 15:07:11 +020016673 err = alc_auto_add_mic_boost(codec);
16674 if (err < 0)
16675 return err;
16676
Kailang Yang6227cdc2010-02-25 08:36:52 +010016677 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016678
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016679 return 1;
16680}
16681
16682/* additional initialization for auto-configuration model */
16683static void alc861vd_auto_init(struct hda_codec *codec)
16684{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016685 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020016686 alc_auto_init_multi_out(codec);
16687 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020016688 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020016689 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016690 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016691 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016692 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016693}
16694
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016695enum {
16696 ALC660VD_FIX_ASUS_GPIO1
16697};
16698
16699/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016700static const struct alc_fixup alc861vd_fixups[] = {
16701 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016702 .type = ALC_FIXUP_VERBS,
16703 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020016704 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16705 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16706 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16707 { }
16708 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016709 },
16710};
16711
Takashi Iwaia9111322011-05-02 11:30:18 +020016712static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016713 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16714 {}
16715};
16716
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016717static int patch_alc861vd(struct hda_codec *codec)
16718{
16719 struct alc_spec *spec;
16720 int err, board_config;
16721
16722 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16723 if (spec == NULL)
16724 return -ENOMEM;
16725
16726 codec->spec = spec;
16727
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020016728 spec->mixer_nid = 0x0b;
16729
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016730 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16731 alc861vd_models,
16732 alc861vd_cfg_tbl);
16733
16734 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016735 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16736 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016737 board_config = ALC861VD_AUTO;
16738 }
16739
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016740 if (board_config == ALC861VD_AUTO) {
16741 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
16742 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16743 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016744
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016745 if (board_config == ALC861VD_AUTO) {
16746 /* automatic parse from the BIOS config */
16747 err = alc861vd_parse_auto_config(codec);
16748 if (err < 0) {
16749 alc_free(codec);
16750 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016751 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016752 printk(KERN_INFO
16753 "hda_codec: Cannot set up configuration "
16754 "from BIOS. Using base mode...\n");
16755 board_config = ALC861VD_3ST;
16756 }
16757 }
16758
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016759 err = snd_hda_attach_beep_device(codec, 0x23);
16760 if (err < 0) {
16761 alc_free(codec);
16762 return err;
16763 }
16764
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016765 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016766 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016767
Kailang Yang2f893282008-05-27 12:14:47 +020016768 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016769 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016770 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016771 }
16772
Takashi Iwaidd704692009-08-11 08:45:11 +020016773 if (!spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020016774 alc_auto_fill_adc_caps(codec);
16775 alc_remove_invalid_adc_nids(codec);
Takashi Iwaidd704692009-08-11 08:45:11 +020016776 }
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016777
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016778 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016779 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016780
Takashi Iwai2134ea42008-01-10 16:53:55 +010016781 spec->vmaster_nid = 0x02;
16782
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016783 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016784
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016785 codec->patch_ops = alc_patch_ops;
16786
16787 if (board_config == ALC861VD_AUTO)
16788 spec->init_hook = alc861vd_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020016789 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016790#ifdef CONFIG_SND_HDA_POWER_SAVE
16791 if (!spec->loopback.amplist)
16792 spec->loopback.amplist = alc861vd_loopbacks;
16793#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016794
16795 return 0;
16796}
16797
16798/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016799 * ALC662 support
16800 *
16801 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16802 * configuration. Each pin widget can choose any input DACs and a mixer.
16803 * Each ADC is connected from a mixer of all inputs. This makes possible
16804 * 6-channel independent captures.
16805 *
16806 * In addition, an independent DAC for the multi-playback (not used in this
16807 * driver yet).
16808 */
16809#define ALC662_DIGOUT_NID 0x06
16810#define ALC662_DIGIN_NID 0x0a
16811
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016812static const hda_nid_t alc662_dac_nids[3] = {
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080016813 /* front, rear, clfe */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016814 0x02, 0x03, 0x04
16815};
16816
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016817static const hda_nid_t alc272_dac_nids[2] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020016818 0x02, 0x03
16819};
16820
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016821static const hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016822 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016823 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016824};
Takashi Iwaie1406342008-02-11 18:32:32 +010016825
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016826static const hda_nid_t alc272_adc_nids[1] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020016827 /* ADC1-2 */
16828 0x08,
16829};
16830
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016831static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
16832static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016833
Takashi Iwaie1406342008-02-11 18:32:32 +010016834
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016835/* input MUX */
16836/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020016837static const struct hda_input_mux alc662_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016838 .num_items = 4,
16839 .items = {
16840 { "Mic", 0x0 },
16841 { "Front Mic", 0x1 },
16842 { "Line", 0x2 },
16843 { "CD", 0x4 },
16844 },
16845};
16846
Takashi Iwaia9111322011-05-02 11:30:18 +020016847static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016848 .num_items = 2,
16849 .items = {
16850 { "Mic", 0x1 },
16851 { "Line", 0x2 },
16852 },
16853};
Kailang Yang291702f2007-10-16 14:28:03 +020016854
Takashi Iwaia9111322011-05-02 11:30:18 +020016855static const struct hda_input_mux alc663_capture_source = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020016856 .num_items = 3,
16857 .items = {
16858 { "Mic", 0x0 },
16859 { "Front Mic", 0x1 },
16860 { "Line", 0x2 },
16861 },
16862};
16863
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016864#if 0 /* set to 1 for testing other input sources below */
Takashi Iwaia9111322011-05-02 11:30:18 +020016865static const struct hda_input_mux alc272_nc10_capture_source = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020016866 .num_items = 16,
16867 .items = {
16868 { "Autoselect Mic", 0x0 },
16869 { "Internal Mic", 0x1 },
16870 { "In-0x02", 0x2 },
16871 { "In-0x03", 0x3 },
16872 { "In-0x04", 0x4 },
16873 { "In-0x05", 0x5 },
16874 { "In-0x06", 0x6 },
16875 { "In-0x07", 0x7 },
16876 { "In-0x08", 0x8 },
16877 { "In-0x09", 0x9 },
16878 { "In-0x0a", 0x0a },
16879 { "In-0x0b", 0x0b },
16880 { "In-0x0c", 0x0c },
16881 { "In-0x0d", 0x0d },
16882 { "In-0x0e", 0x0e },
16883 { "In-0x0f", 0x0f },
16884 },
16885};
16886#endif
16887
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016888/*
16889 * 2ch mode
16890 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016891static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016892 { 2, NULL }
16893};
16894
16895/*
16896 * 2ch mode
16897 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016898static const struct hda_verb alc662_3ST_ch2_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016899 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16900 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16901 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16902 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16903 { } /* end */
16904};
16905
16906/*
16907 * 6ch mode
16908 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016909static const struct hda_verb alc662_3ST_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016910 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16911 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16912 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16913 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16914 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16915 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16916 { } /* end */
16917};
16918
Takashi Iwaia9111322011-05-02 11:30:18 +020016919static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016920 { 2, alc662_3ST_ch2_init },
16921 { 6, alc662_3ST_ch6_init },
16922};
16923
16924/*
16925 * 2ch mode
16926 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016927static const struct hda_verb alc662_sixstack_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016928 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16929 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16930 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16931 { } /* end */
16932};
16933
16934/*
16935 * 6ch mode
16936 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016937static const struct hda_verb alc662_sixstack_ch8_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016938 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16939 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16940 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16941 { } /* end */
16942};
16943
Takashi Iwaia9111322011-05-02 11:30:18 +020016944static const struct hda_channel_mode alc662_5stack_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016945 { 2, alc662_sixstack_ch6_init },
16946 { 6, alc662_sixstack_ch8_init },
16947};
16948
16949/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16950 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16951 */
16952
Takashi Iwaia9111322011-05-02 11:30:18 +020016953static const struct snd_kcontrol_new alc662_base_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016954 /* output mixer control */
16955 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016956 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016957 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016958 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016959 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16960 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016961 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16962 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016963 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16964
16965 /*Input mixer control */
16966 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16967 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16968 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16969 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16970 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16971 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16972 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16973 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016974 { } /* end */
16975};
16976
Takashi Iwaia9111322011-05-02 11:30:18 +020016977static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016978 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016979 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016980 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16981 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16982 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16983 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16984 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16985 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16986 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16987 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16988 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016989 { } /* end */
16990};
16991
Takashi Iwaia9111322011-05-02 11:30:18 +020016992static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016993 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016994 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016995 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016996 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016997 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16998 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016999 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17000 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017001 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17002 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17003 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17004 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17005 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17006 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17007 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17008 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17009 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017010 { } /* end */
17011};
17012
Takashi Iwaia9111322011-05-02 11:30:18 +020017013static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017014 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17015 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017016 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17017 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017018 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17019 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17020 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17021 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17022 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017023 { } /* end */
17024};
17025
Takashi Iwaia9111322011-05-02 11:30:18 +020017026static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017027 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17028 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017029
David Henningsson5f99f862011-01-04 15:24:24 +010017030 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017031 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17032 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017033
David Henningsson5f99f862011-01-04 15:24:24 +010017034 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017035 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17036 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017037 { } /* end */
17038};
17039
Takashi Iwaia9111322011-05-02 11:30:18 +020017040static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017041 ALC262_HIPPO_MASTER_SWITCH,
17042 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017043 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017044 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17045 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017046 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17047 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17048 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17049 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17050 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17051 { } /* end */
17052};
17053
Takashi Iwaia9111322011-05-02 11:30:18 +020017054static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017055 .ops = &snd_hda_bind_vol,
17056 .values = {
17057 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17058 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17059 0
17060 },
17061};
17062
Takashi Iwaia9111322011-05-02 11:30:18 +020017063static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017064 .ops = &snd_hda_bind_sw,
17065 .values = {
17066 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17067 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17068 0
17069 },
17070};
17071
Takashi Iwaia9111322011-05-02 11:30:18 +020017072static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017073 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17074 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17075 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17076 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17077 { } /* end */
17078};
17079
Takashi Iwaia9111322011-05-02 11:30:18 +020017080static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017081 .ops = &snd_hda_bind_sw,
17082 .values = {
17083 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17084 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17085 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17086 0
17087 },
17088};
17089
Takashi Iwaia9111322011-05-02 11:30:18 +020017090static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017091 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17092 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17093 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17094 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17095 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17096 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17097
17098 { } /* end */
17099};
17100
Takashi Iwaia9111322011-05-02 11:30:18 +020017101static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017102 .ops = &snd_hda_bind_sw,
17103 .values = {
17104 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17105 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17106 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17107 0
17108 },
17109};
17110
Takashi Iwaia9111322011-05-02 11:30:18 +020017111static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017112 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17113 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17114 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17115 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17116 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17117 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17118 { } /* end */
17119};
17120
Takashi Iwaia9111322011-05-02 11:30:18 +020017121static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017122 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17123 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017124 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17125 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17126 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17127 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17128 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17129 { } /* end */
17130};
17131
Takashi Iwaia9111322011-05-02 11:30:18 +020017132static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017133 .ops = &snd_hda_bind_vol,
17134 .values = {
17135 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17136 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17137 0
17138 },
17139};
17140
Takashi Iwaia9111322011-05-02 11:30:18 +020017141static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017142 .ops = &snd_hda_bind_sw,
17143 .values = {
17144 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17145 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17146 0
17147 },
17148};
17149
Takashi Iwaia9111322011-05-02 11:30:18 +020017150static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017151 HDA_BIND_VOL("Master Playback Volume",
17152 &alc663_asus_two_bind_master_vol),
17153 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17154 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017155 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17156 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17157 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017158 { } /* end */
17159};
17160
Takashi Iwaia9111322011-05-02 11:30:18 +020017161static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017162 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17163 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17164 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17165 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17166 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17167 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017168 { } /* end */
17169};
17170
Takashi Iwaia9111322011-05-02 11:30:18 +020017171static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017172 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17173 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17174 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17175 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17176 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17177
17178 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17179 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017180 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17181 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017182 { } /* end */
17183};
17184
Takashi Iwaia9111322011-05-02 11:30:18 +020017185static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017186 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17187 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17188 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17189
17190 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17191 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017192 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17193 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017194 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17195 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17196 { } /* end */
17197};
17198
Takashi Iwaia9111322011-05-02 11:30:18 +020017199static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017200 .ops = &snd_hda_bind_sw,
17201 .values = {
17202 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17203 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17204 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17205 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17206 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17207 0
17208 },
17209};
17210
Takashi Iwaia9111322011-05-02 11:30:18 +020017211static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017212 .ops = &snd_hda_bind_sw,
17213 .values = {
17214 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17215 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17216 0
17217 },
17218};
17219
Takashi Iwaia9111322011-05-02 11:30:18 +020017220static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017221 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17222 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17223 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17224 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17225 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17226 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17227 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17228 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17229 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17230 { } /* end */
17231};
17232
Takashi Iwaia9111322011-05-02 11:30:18 +020017233static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017234 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17235 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17236 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17237 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17238 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17239 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17240 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17241 { } /* end */
17242};
17243
17244
Takashi Iwaia9111322011-05-02 11:30:18 +020017245static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017246 {
17247 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17248 .name = "Channel Mode",
17249 .info = alc_ch_mode_info,
17250 .get = alc_ch_mode_get,
17251 .put = alc_ch_mode_put,
17252 },
17253 { } /* end */
17254};
17255
Takashi Iwaia9111322011-05-02 11:30:18 +020017256static const struct hda_verb alc662_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017257 /* ADC: mute amp left and right */
17258 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17259 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017260
Kailang Yangb60dd392007-09-20 12:50:29 +020017261 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17262 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17263 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17264 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17265 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17266 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017267
17268 /* Front Pin: output 0 (0x0c) */
17269 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17270 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17271
17272 /* Rear Pin: output 1 (0x0d) */
17273 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17274 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17275
17276 /* CLFE Pin: output 2 (0x0e) */
17277 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17278 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17279
17280 /* Mic (rear) pin: input vref at 80% */
17281 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17282 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17283 /* Front Mic pin: input vref at 80% */
17284 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17285 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17286 /* Line In pin: input */
17287 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17288 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17289 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17290 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17291 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17292 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17293 /* CD pin widget for input */
17294 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17295
17296 /* FIXME: use matrix-type input source selection */
17297 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17298 /* Input mixer */
17299 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017300 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017301
Takashi Iwaia7f23712011-04-07 10:24:23 +020017302 { }
17303};
17304
Takashi Iwaia9111322011-05-02 11:30:18 +020017305static const struct hda_verb alc662_eapd_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017306 /* always trun on EAPD */
17307 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17308 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017309 { }
17310};
17311
Takashi Iwaia9111322011-05-02 11:30:18 +020017312static const struct hda_verb alc662_sue_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017313 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17314 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017315 {}
17316};
17317
Takashi Iwaia9111322011-05-02 11:30:18 +020017318static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020017319 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17320 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17321 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017322};
17323
Kailang Yang8c427222008-01-10 13:03:59 +010017324/* Set Unsolicited Event*/
Takashi Iwaia9111322011-05-02 11:30:18 +020017325static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010017326 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17327 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17328 {}
17329};
17330
Takashi Iwaia9111322011-05-02 11:30:18 +020017331static const struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017332 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17333 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017334 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17335 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017336 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17337 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17338 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017339 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17340 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17341 {}
17342};
17343
Takashi Iwaia9111322011-05-02 11:30:18 +020017344static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017345 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17346 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17347 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17348 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17349 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17350 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17351 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17352 {}
17353};
17354
Takashi Iwaia9111322011-05-02 11:30:18 +020017355static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017356 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17357 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17358 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17359 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17360 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17361 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17362 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17363 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17364 {}
17365};
17366
Takashi Iwaia9111322011-05-02 11:30:18 +020017367static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017368 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17369 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17370 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17371 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17372 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17373 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17374 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17375 {}
17376};
17377
Takashi Iwaia9111322011-05-02 11:30:18 +020017378static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017379 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17380 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17381 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17382 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17383 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17384 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17385 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17388 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17389 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17390 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17391 {}
17392};
17393
Takashi Iwaia9111322011-05-02 11:30:18 +020017394static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017395 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17396 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17397 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17398 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17399 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17400 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17401 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17402 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17403 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17404 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17405 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17406 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17407 {}
17408};
17409
Takashi Iwaia9111322011-05-02 11:30:18 +020017410static const struct hda_verb alc663_g71v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017411 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17412 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17413 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17414
17415 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17416 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17417 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17418
17419 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17420 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17421 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17422 {}
17423};
17424
Takashi Iwaia9111322011-05-02 11:30:18 +020017425static const struct hda_verb alc663_g50v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017426 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17427 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17428 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17429
17430 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17431 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17432 {}
17433};
17434
Takashi Iwaia9111322011-05-02 11:30:18 +020017435static const struct hda_verb alc662_ecs_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017436 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17437 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17438 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17439 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17440 {}
17441};
17442
Takashi Iwaia9111322011-05-02 11:30:18 +020017443static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017444 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17445 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17446 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17447 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17448 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17449 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17450 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17451 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17453 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17454 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17455 {}
17456};
17457
Takashi Iwaia9111322011-05-02 11:30:18 +020017458static const struct hda_verb alc272_dell_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017459 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17460 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17461 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17462 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17463 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17464 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17465 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17466 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17467 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17468 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17469 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17470 {}
17471};
17472
Takashi Iwaia9111322011-05-02 11:30:18 +020017473static const struct hda_verb alc663_mode7_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017474 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17475 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17476 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17477 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17478 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17479 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17480 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17481 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17482 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17483 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17484 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17485 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17486 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17487 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17488 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17489 {}
17490};
17491
Takashi Iwaia9111322011-05-02 11:30:18 +020017492static const struct hda_verb alc663_mode8_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017493 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17494 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17495 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17496 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17497 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17498 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17499 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17500 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17501 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17502 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17503 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17504 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17505 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17506 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17507 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17508 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17509 {}
17510};
17511
Takashi Iwaia9111322011-05-02 11:30:18 +020017512static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017513 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17514 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17515 { } /* end */
17516};
17517
Takashi Iwaia9111322011-05-02 11:30:18 +020017518static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017519 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17520 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17521 { } /* end */
17522};
17523
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017524static void alc662_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017525{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017526 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017527
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017528 spec->autocfg.hp_pins[0] = 0x1b;
17529 spec->autocfg.line_out_pins[0] = 0x14;
17530 spec->autocfg.speaker_pins[0] = 0x15;
17531 spec->automute = 1;
17532 spec->detect_line = 1;
17533 spec->automute_lines = 1;
17534 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017535}
17536
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017537static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017538{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017539 struct alc_spec *spec = codec->spec;
17540
17541 alc262_hippo1_setup(codec);
17542 spec->ext_mic.pin = 0x18;
17543 spec->ext_mic.mux_idx = 0;
17544 spec->int_mic.pin = 0x19;
17545 spec->int_mic.mux_idx = 1;
17546 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017547}
17548
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017549static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017550{
Takashi Iwai42171c12009-05-08 14:11:43 +020017551 struct alc_spec *spec = codec->spec;
17552
17553 spec->autocfg.hp_pins[0] = 0x14;
17554 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaie9427962011-04-28 15:46:07 +020017555 spec->automute = 1;
17556 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang8c427222008-01-10 13:03:59 +010017557}
17558
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017559static void alc663_m51va_setup(struct hda_codec *codec)
17560{
17561 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017562 spec->autocfg.hp_pins[0] = 0x21;
17563 spec->autocfg.speaker_pins[0] = 0x14;
17564 spec->automute_mixer_nid[0] = 0x0c;
17565 spec->automute = 1;
17566 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017567 spec->ext_mic.pin = 0x18;
17568 spec->ext_mic.mux_idx = 0;
17569 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017570 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017571 spec->auto_mic = 1;
17572}
17573
Kailang Yangf1d4e282008-08-26 14:03:29 +020017574/* ***************** Mode1 ******************************/
Kailang Yangebb83ee2009-12-17 12:23:00 +010017575static void alc663_mode1_setup(struct hda_codec *codec)
17576{
17577 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017578 spec->autocfg.hp_pins[0] = 0x21;
17579 spec->autocfg.speaker_pins[0] = 0x14;
17580 spec->automute_mixer_nid[0] = 0x0c;
17581 spec->automute = 1;
17582 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017583 spec->ext_mic.pin = 0x18;
17584 spec->ext_mic.mux_idx = 0;
17585 spec->int_mic.pin = 0x19;
17586 spec->int_mic.mux_idx = 1;
17587 spec->auto_mic = 1;
17588}
17589
Kailang Yangf1d4e282008-08-26 14:03:29 +020017590/* ***************** Mode2 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017591static void alc662_mode2_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017592{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017593 struct alc_spec *spec = codec->spec;
17594 spec->autocfg.hp_pins[0] = 0x1b;
17595 spec->autocfg.speaker_pins[0] = 0x14;
17596 spec->automute = 1;
17597 spec->automute_mode = ALC_AUTOMUTE_PIN;
17598 spec->ext_mic.pin = 0x18;
17599 spec->ext_mic.mux_idx = 0;
17600 spec->int_mic.pin = 0x19;
17601 spec->int_mic.mux_idx = 1;
17602 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017603}
17604
Kailang Yangf1d4e282008-08-26 14:03:29 +020017605/* ***************** Mode3 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017606static void alc663_mode3_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017607{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017608 struct alc_spec *spec = codec->spec;
17609 spec->autocfg.hp_pins[0] = 0x21;
17610 spec->autocfg.hp_pins[0] = 0x15;
17611 spec->autocfg.speaker_pins[0] = 0x14;
17612 spec->automute = 1;
17613 spec->automute_mode = ALC_AUTOMUTE_PIN;
17614 spec->ext_mic.pin = 0x18;
17615 spec->ext_mic.mux_idx = 0;
17616 spec->int_mic.pin = 0x19;
17617 spec->int_mic.mux_idx = 1;
17618 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017619}
17620
Kailang Yangf1d4e282008-08-26 14:03:29 +020017621/* ***************** Mode4 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017622static void alc663_mode4_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017623{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017624 struct alc_spec *spec = codec->spec;
17625 spec->autocfg.hp_pins[0] = 0x21;
17626 spec->autocfg.speaker_pins[0] = 0x14;
17627 spec->autocfg.speaker_pins[1] = 0x16;
17628 spec->automute_mixer_nid[0] = 0x0c;
17629 spec->automute_mixer_nid[1] = 0x0e;
17630 spec->automute = 1;
17631 spec->automute_mode = ALC_AUTOMUTE_MIXER;
17632 spec->ext_mic.pin = 0x18;
17633 spec->ext_mic.mux_idx = 0;
17634 spec->int_mic.pin = 0x19;
17635 spec->int_mic.mux_idx = 1;
17636 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017637}
17638
Kailang Yangf1d4e282008-08-26 14:03:29 +020017639/* ***************** Mode5 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017640static void alc663_mode5_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017641{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017642 struct alc_spec *spec = codec->spec;
17643 spec->autocfg.hp_pins[0] = 0x15;
17644 spec->autocfg.speaker_pins[0] = 0x14;
17645 spec->autocfg.speaker_pins[1] = 0x16;
17646 spec->automute_mixer_nid[0] = 0x0c;
17647 spec->automute_mixer_nid[1] = 0x0e;
17648 spec->automute = 1;
17649 spec->automute_mode = ALC_AUTOMUTE_MIXER;
17650 spec->ext_mic.pin = 0x18;
17651 spec->ext_mic.mux_idx = 0;
17652 spec->int_mic.pin = 0x19;
17653 spec->int_mic.mux_idx = 1;
17654 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017655}
17656
Kailang Yangf1d4e282008-08-26 14:03:29 +020017657/* ***************** Mode6 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017658static void alc663_mode6_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017659{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017660 struct alc_spec *spec = codec->spec;
17661 spec->autocfg.hp_pins[0] = 0x1b;
17662 spec->autocfg.hp_pins[0] = 0x15;
17663 spec->autocfg.speaker_pins[0] = 0x14;
17664 spec->automute_mixer_nid[0] = 0x0c;
17665 spec->automute = 1;
17666 spec->automute_mode = ALC_AUTOMUTE_MIXER;
17667 spec->ext_mic.pin = 0x18;
17668 spec->ext_mic.mux_idx = 0;
17669 spec->int_mic.pin = 0x19;
17670 spec->int_mic.mux_idx = 1;
17671 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017672}
17673
Kailang Yangebb83ee2009-12-17 12:23:00 +010017674/* ***************** Mode7 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017675static void alc663_mode7_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010017676{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017677 struct alc_spec *spec = codec->spec;
17678 spec->autocfg.hp_pins[0] = 0x1b;
17679 spec->autocfg.hp_pins[0] = 0x21;
17680 spec->autocfg.speaker_pins[0] = 0x14;
17681 spec->autocfg.speaker_pins[0] = 0x17;
17682 spec->automute = 1;
17683 spec->automute_mode = ALC_AUTOMUTE_PIN;
17684 spec->ext_mic.pin = 0x18;
17685 spec->ext_mic.mux_idx = 0;
17686 spec->int_mic.pin = 0x19;
17687 spec->int_mic.mux_idx = 1;
17688 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017689}
17690
17691/* ***************** Mode8 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017692static void alc663_mode8_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010017693{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017694 struct alc_spec *spec = codec->spec;
17695 spec->autocfg.hp_pins[0] = 0x21;
17696 spec->autocfg.hp_pins[1] = 0x15;
17697 spec->autocfg.speaker_pins[0] = 0x14;
17698 spec->autocfg.speaker_pins[0] = 0x17;
17699 spec->automute = 1;
17700 spec->automute_mode = ALC_AUTOMUTE_PIN;
17701 spec->ext_mic.pin = 0x18;
17702 spec->ext_mic.mux_idx = 0;
17703 spec->int_mic.pin = 0x12;
17704 spec->int_mic.mux_idx = 9;
17705 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017706}
17707
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017708static void alc663_g71v_setup(struct hda_codec *codec)
Kailang Yang6dda9f42008-05-27 12:05:31 +020017709{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017710 struct alc_spec *spec = codec->spec;
17711 spec->autocfg.hp_pins[0] = 0x21;
17712 spec->autocfg.line_out_pins[0] = 0x15;
17713 spec->autocfg.speaker_pins[0] = 0x14;
17714 spec->automute = 1;
17715 spec->automute_mode = ALC_AUTOMUTE_AMP;
17716 spec->detect_line = 1;
17717 spec->automute_lines = 1;
17718 spec->ext_mic.pin = 0x18;
17719 spec->ext_mic.mux_idx = 0;
17720 spec->int_mic.pin = 0x12;
17721 spec->int_mic.mux_idx = 9;
17722 spec->auto_mic = 1;
Kailang Yang6dda9f42008-05-27 12:05:31 +020017723}
17724
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017725#define alc663_g50v_setup alc663_m51va_setup
17726
Takashi Iwaia9111322011-05-02 11:30:18 +020017727static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017728 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020017729 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017730
David Henningsson5f99f862011-01-04 15:24:24 +010017731 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017732 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
17733 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017734
David Henningsson5f99f862011-01-04 15:24:24 +010017735 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017736 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17737 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017738 { } /* end */
17739};
17740
Takashi Iwaia9111322011-05-02 11:30:18 +020017741static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020017742 /* Master Playback automatically created from Speaker and Headphone */
17743 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17744 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17745 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17746 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17747
David Henningsson8607f7c2010-12-20 14:43:54 +010017748 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17749 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010017750 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017751
David Henningsson28c4edb2010-12-20 14:24:29 +010017752 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17753 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010017754 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017755 { } /* end */
17756};
17757
Takashi Iwaicb53c622007-08-10 17:21:45 +020017758#ifdef CONFIG_SND_HDA_POWER_SAVE
17759#define alc662_loopbacks alc880_loopbacks
17760#endif
17761
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017762
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017763/*
17764 * configuration and preset
17765 */
Takashi Iwaiea734962011-01-17 11:29:34 +010017766static const char * const alc662_models[ALC662_MODEL_LAST] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017767 [ALC662_3ST_2ch_DIG] = "3stack-dig",
17768 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
17769 [ALC662_3ST_6ch] = "3stack-6ch",
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080017770 [ALC662_5ST_DIG] = "5stack-dig",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017771 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020017772 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010017773 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017774 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020017775 [ALC663_ASUS_M51VA] = "m51va",
17776 [ALC663_ASUS_G71V] = "g71v",
17777 [ALC663_ASUS_H13] = "h13",
17778 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017779 [ALC663_ASUS_MODE1] = "asus-mode1",
17780 [ALC662_ASUS_MODE2] = "asus-mode2",
17781 [ALC663_ASUS_MODE3] = "asus-mode3",
17782 [ALC663_ASUS_MODE4] = "asus-mode4",
17783 [ALC663_ASUS_MODE5] = "asus-mode5",
17784 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010017785 [ALC663_ASUS_MODE7] = "asus-mode7",
17786 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020017787 [ALC272_DELL] = "dell",
17788 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020017789 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017790 [ALC662_AUTO] = "auto",
17791};
17792
Takashi Iwaia9111322011-05-02 11:30:18 +020017793static const struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010017794 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020017795 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
17796 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017797 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
17798 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010017799 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017800 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
17801 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
17802 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
17803 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017804 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
17805 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017806 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017807 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
17808 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
17809 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
17810 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
17811 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017812 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017813 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
17814 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017815 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
17816 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
17817 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
17818 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017819 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020017820 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
17821 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
17822 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017823 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
17824 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
17825 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
17826 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017827 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017828 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
17829 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017830 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017831 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
17832 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
17833 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017834 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010017835 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020017836 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
17837 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017838 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
17839 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
17840 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017841 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017842 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
17843 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017844 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017845 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020017846 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017847 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
17848 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
17849 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017850 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017851 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
17852 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010017853 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020017854 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010017855 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017856 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030017857 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
17858 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010017859 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017860 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Takashi Iwaiebb47242011-05-02 10:37:29 +020017861 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
17862 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010017863 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020017864 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020017865 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017866 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020017867 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020017868 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017869 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
17870 ALC663_ASUS_H13),
Anisse Astier965b76d2011-02-10 13:14:44 +010017871 SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017872 {}
17873};
17874
Takashi Iwaia9111322011-05-02 11:30:18 +020017875static const struct alc_config_preset alc662_presets[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017876 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017877 .mixers = { alc662_3ST_2ch_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017878 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017879 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17880 .dac_nids = alc662_dac_nids,
17881 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017882 .dig_in_nid = ALC662_DIGIN_NID,
17883 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17884 .channel_mode = alc662_3ST_2ch_modes,
17885 .input_mux = &alc662_capture_source,
17886 },
17887 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017888 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017889 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017890 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17891 .dac_nids = alc662_dac_nids,
17892 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017893 .dig_in_nid = ALC662_DIGIN_NID,
17894 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17895 .channel_mode = alc662_3ST_6ch_modes,
17896 .need_dac_fix = 1,
17897 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017898 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017899 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017900 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017901 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017902 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17903 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017904 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17905 .channel_mode = alc662_3ST_6ch_modes,
17906 .need_dac_fix = 1,
17907 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017908 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017909 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017910 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017911 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017912 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17913 .dac_nids = alc662_dac_nids,
17914 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017915 .dig_in_nid = ALC662_DIGIN_NID,
17916 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
17917 .channel_mode = alc662_5stack_modes,
17918 .input_mux = &alc662_capture_source,
17919 },
17920 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017921 .mixers = { alc662_lenovo_101e_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017922 .init_verbs = { alc662_init_verbs,
17923 alc662_eapd_init_verbs,
17924 alc662_sue_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017925 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17926 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017927 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17928 .channel_mode = alc662_3ST_2ch_modes,
17929 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017930 .unsol_event = alc_sku_unsol_event,
17931 .setup = alc662_lenovo_101e_setup,
17932 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017933 },
Kailang Yang291702f2007-10-16 14:28:03 +020017934 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017935 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020017936 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017937 alc662_eapd_init_verbs,
Kailang Yang291702f2007-10-16 14:28:03 +020017938 alc662_eeepc_sue_init_verbs },
17939 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17940 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020017941 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17942 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020017943 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017944 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020017945 .init_hook = alc_inithook,
Kailang Yang291702f2007-10-16 14:28:03 +020017946 },
Kailang Yang8c427222008-01-10 13:03:59 +010017947 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017948 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010017949 alc662_chmode_mixer },
17950 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017951 alc662_eapd_init_verbs,
Kailang Yang8c427222008-01-10 13:03:59 +010017952 alc662_eeepc_ep20_sue_init_verbs },
17953 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17954 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010017955 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17956 .channel_mode = alc662_3ST_6ch_modes,
17957 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020017958 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017959 .setup = alc662_eeepc_ep20_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020017960 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010017961 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017962 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017963 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017964 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017965 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017966 alc662_ecs_init_verbs },
17967 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17968 .dac_nids = alc662_dac_nids,
17969 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17970 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020017971 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017972 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020017973 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017974 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017975 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017976 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017977 .init_verbs = { alc662_init_verbs,
17978 alc662_eapd_init_verbs,
17979 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017980 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17981 .dac_nids = alc662_dac_nids,
17982 .dig_out_nid = ALC662_DIGOUT_NID,
17983 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17984 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017985 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017986 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017987 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017988 },
17989 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017990 .mixers = { alc663_g71v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017991 .init_verbs = { alc662_init_verbs,
17992 alc662_eapd_init_verbs,
17993 alc663_g71v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017994 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17995 .dac_nids = alc662_dac_nids,
17996 .dig_out_nid = ALC662_DIGOUT_NID,
17997 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17998 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017999 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018000 .setup = alc663_g71v_setup,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018001 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018002 },
18003 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018004 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018005 .init_verbs = { alc662_init_verbs,
18006 alc662_eapd_init_verbs,
18007 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018008 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18009 .dac_nids = alc662_dac_nids,
18010 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18011 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018012 .setup = alc663_m51va_setup,
18013 .unsol_event = alc_sku_unsol_event,
18014 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018015 },
18016 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018017 .mixers = { alc663_g50v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018018 .init_verbs = { alc662_init_verbs,
18019 alc662_eapd_init_verbs,
18020 alc663_g50v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018021 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18022 .dac_nids = alc662_dac_nids,
18023 .dig_out_nid = ALC662_DIGOUT_NID,
18024 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18025 .channel_mode = alc662_3ST_6ch_modes,
18026 .input_mux = &alc663_capture_source,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018027 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018028 .setup = alc663_g50v_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018029 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018030 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018031 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018032 .mixers = { alc663_m51va_mixer },
18033 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018034 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018035 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018036 alc663_21jd_amic_init_verbs },
18037 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18038 .hp_nid = 0x03,
18039 .dac_nids = alc662_dac_nids,
18040 .dig_out_nid = ALC662_DIGOUT_NID,
18041 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18042 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018043 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018044 .setup = alc663_mode1_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018045 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018046 },
18047 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018048 .mixers = { alc662_1bjd_mixer },
18049 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018050 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018051 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018052 alc662_1bjd_amic_init_verbs },
18053 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18054 .dac_nids = alc662_dac_nids,
18055 .dig_out_nid = ALC662_DIGOUT_NID,
18056 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18057 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018058 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018059 .setup = alc662_mode2_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018060 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018061 },
18062 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018063 .mixers = { alc663_two_hp_m1_mixer },
18064 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018065 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018066 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018067 alc663_two_hp_amic_m1_init_verbs },
18068 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18069 .hp_nid = 0x03,
18070 .dac_nids = alc662_dac_nids,
18071 .dig_out_nid = ALC662_DIGOUT_NID,
18072 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18073 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018074 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018075 .setup = alc663_mode3_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018076 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018077 },
18078 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018079 .mixers = { alc663_asus_21jd_clfe_mixer },
18080 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018081 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018082 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018083 alc663_21jd_amic_init_verbs},
18084 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18085 .hp_nid = 0x03,
18086 .dac_nids = alc662_dac_nids,
18087 .dig_out_nid = ALC662_DIGOUT_NID,
18088 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18089 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018090 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018091 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018092 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018093 },
18094 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018095 .mixers = { alc663_asus_15jd_clfe_mixer },
18096 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018097 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018098 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018099 alc663_15jd_amic_init_verbs },
18100 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18101 .hp_nid = 0x03,
18102 .dac_nids = alc662_dac_nids,
18103 .dig_out_nid = ALC662_DIGOUT_NID,
18104 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18105 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018106 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018107 .setup = alc663_mode5_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018108 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018109 },
18110 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018111 .mixers = { alc663_two_hp_m2_mixer },
18112 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018113 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018114 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018115 alc663_two_hp_amic_m2_init_verbs },
18116 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18117 .hp_nid = 0x03,
18118 .dac_nids = alc662_dac_nids,
18119 .dig_out_nid = ALC662_DIGOUT_NID,
18120 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18121 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018122 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018123 .setup = alc663_mode6_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018124 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018125 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018126 [ALC663_ASUS_MODE7] = {
18127 .mixers = { alc663_mode7_mixer },
18128 .cap_mixer = alc662_auto_capture_mixer,
18129 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018130 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018131 alc663_mode7_init_verbs },
18132 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18133 .hp_nid = 0x03,
18134 .dac_nids = alc662_dac_nids,
18135 .dig_out_nid = ALC662_DIGOUT_NID,
18136 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18137 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018138 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018139 .setup = alc663_mode7_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018140 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018141 },
18142 [ALC663_ASUS_MODE8] = {
18143 .mixers = { alc663_mode8_mixer },
18144 .cap_mixer = alc662_auto_capture_mixer,
18145 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018146 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018147 alc663_mode8_init_verbs },
18148 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18149 .hp_nid = 0x03,
18150 .dac_nids = alc662_dac_nids,
18151 .dig_out_nid = ALC662_DIGOUT_NID,
18152 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18153 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018154 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018155 .setup = alc663_mode8_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018156 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018157 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018158 [ALC272_DELL] = {
18159 .mixers = { alc663_m51va_mixer },
18160 .cap_mixer = alc272_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018161 .init_verbs = { alc662_init_verbs,
18162 alc662_eapd_init_verbs,
18163 alc272_dell_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018164 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018165 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018166 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18167 .adc_nids = alc272_adc_nids,
18168 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18169 .capsrc_nids = alc272_capsrc_nids,
18170 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018171 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018172 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018173 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018174 },
18175 [ALC272_DELL_ZM1] = {
18176 .mixers = { alc663_m51va_mixer },
18177 .cap_mixer = alc662_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018178 .init_verbs = { alc662_init_verbs,
18179 alc662_eapd_init_verbs,
18180 alc272_dell_zm1_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018181 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018182 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018183 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18184 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018185 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018186 .capsrc_nids = alc662_capsrc_nids,
18187 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018188 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018189 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018190 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018191 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018192 [ALC272_SAMSUNG_NC10] = {
18193 .mixers = { alc272_nc10_mixer },
18194 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018195 alc662_eapd_init_verbs,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018196 alc663_21jd_amic_init_verbs },
18197 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18198 .dac_nids = alc272_dac_nids,
18199 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18200 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018201 /*.input_mux = &alc272_nc10_capture_source,*/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018202 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018203 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018204 .init_hook = alc_inithook,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018205 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018206};
18207
18208
18209/*
18210 * BIOS auto configuration
18211 */
18212
Takashi Iwai7085ec12009-10-02 09:03:58 +020018213/* convert from MIX nid to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018214static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018215{
Takashi Iwai604401a2011-04-27 15:14:23 +020018216 hda_nid_t list[5];
Takashi Iwai1304ac82011-04-06 15:16:21 +020018217 int i, num;
18218
18219 num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
18220 for (i = 0; i < num; i++) {
18221 if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
18222 return list[i];
18223 }
18224 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018225}
18226
Takashi Iwai604401a2011-04-27 15:14:23 +020018227/* go down to the selector widget before the mixer */
18228static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
18229{
18230 hda_nid_t srcs[5];
18231 int num = snd_hda_get_connections(codec, pin, srcs,
18232 ARRAY_SIZE(srcs));
18233 if (num != 1 ||
18234 get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
18235 return pin;
18236 return srcs[0];
18237}
18238
Takashi Iwai7085ec12009-10-02 09:03:58 +020018239/* get MIX nid connected to the given pin targeted to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018240static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018241 hda_nid_t dac)
18242{
David Henningssoncc1c4522010-11-24 14:17:47 +010018243 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018244 int i, num;
18245
Takashi Iwai604401a2011-04-27 15:14:23 +020018246 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018247 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18248 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018249 if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018250 return mix[i];
18251 }
18252 return 0;
18253}
18254
Takashi Iwaice764ab2011-04-27 16:35:23 +020018255/* select the connection from pin to DAC if needed */
18256static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
18257 hda_nid_t dac)
18258{
18259 hda_nid_t mix[5];
18260 int i, num;
18261
18262 pin = alc_go_down_to_selector(codec, pin);
18263 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18264 if (num < 2)
18265 return 0;
18266 for (i = 0; i < num; i++) {
18267 if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
18268 snd_hda_codec_update_cache(codec, pin, 0,
18269 AC_VERB_SET_CONNECT_SEL, i);
18270 return 0;
18271 }
18272 }
18273 return 0;
18274}
18275
Takashi Iwai7085ec12009-10-02 09:03:58 +020018276/* look for an empty DAC slot */
Takashi Iwai604401a2011-04-27 15:14:23 +020018277static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018278{
18279 struct alc_spec *spec = codec->spec;
18280 hda_nid_t srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018281 int i, num;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018282
Takashi Iwai604401a2011-04-27 15:14:23 +020018283 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018284 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018285 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018286 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018287 if (!nid)
18288 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018289 if (found_in_nid_list(nid, spec->multiout.dac_nids,
18290 spec->multiout.num_dacs))
18291 continue;
18292 if (spec->multiout.hp_nid == nid)
18293 continue;
18294 if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
18295 ARRAY_SIZE(spec->multiout.extra_out_nid)))
18296 continue;
18297 return nid;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018298 }
18299 return 0;
18300}
18301
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018302static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
18303{
18304 hda_nid_t sel = alc_go_down_to_selector(codec, pin);
18305 if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
18306 return alc_auto_look_for_dac(codec, pin);
18307 return 0;
18308}
18309
Takashi Iwai7085ec12009-10-02 09:03:58 +020018310/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018311static int alc_auto_fill_dac_nids(struct hda_codec *codec)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018312{
18313 struct alc_spec *spec = codec->spec;
Takashi Iwaicb053a82011-06-27 11:32:07 +020018314 const struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai350434e2011-06-30 21:29:12 +020018315 bool redone = false;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018316 int i;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018317
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018318 again:
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018319 spec->multiout.num_dacs = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018320 spec->multiout.hp_nid = 0;
18321 spec->multiout.extra_out_nid[0] = 0;
18322 memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
18323 spec->multiout.dac_nids = spec->private_dac_nids;
18324
18325 /* fill hard-wired DACs first */
18326 if (!redone) {
18327 for (i = 0; i < cfg->line_outs; i++)
18328 spec->private_dac_nids[i] =
18329 get_dac_if_single(codec, cfg->line_out_pins[i]);
18330 if (cfg->hp_outs)
18331 spec->multiout.hp_nid =
18332 get_dac_if_single(codec, cfg->hp_pins[0]);
18333 if (cfg->speaker_outs)
18334 spec->multiout.extra_out_nid[0] =
18335 get_dac_if_single(codec, cfg->speaker_pins[0]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018336 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018337
18338 for (i = 0; i < cfg->line_outs; i++) {
18339 hda_nid_t pin = cfg->line_out_pins[i];
18340 if (spec->private_dac_nids[i])
18341 continue;
18342 spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
18343 if (!spec->private_dac_nids[i] && !redone) {
18344 /* if we can't find primary DACs, re-probe without
18345 * checking the hard-wired DACs
18346 */
18347 redone = true;
18348 goto again;
18349 }
18350 }
18351
18352 for (i = 0; i < cfg->line_outs; i++) {
18353 if (spec->private_dac_nids[i])
18354 spec->multiout.num_dacs++;
18355 else
18356 memmove(spec->private_dac_nids + i,
18357 spec->private_dac_nids + i + 1,
18358 sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
18359 }
18360
Takashi Iwaibb8bf4d2011-07-06 13:07:54 +020018361 if (cfg->hp_outs && !spec->multiout.hp_nid)
18362 spec->multiout.hp_nid =
18363 alc_auto_look_for_dac(codec, cfg->hp_pins[0]);
18364 if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0])
18365 spec->multiout.extra_out_nid[0] =
18366 alc_auto_look_for_dac(codec, cfg->speaker_pins[0]);
18367
Takashi Iwai7085ec12009-10-02 09:03:58 +020018368 return 0;
18369}
18370
Takashi Iwai343a04b2011-07-06 14:28:39 +020018371static int alc_auto_add_vol_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +020018372 const char *pfx, int cidx,
18373 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018374{
Takashi Iwai97aaab72011-07-06 14:02:55 +020018375 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
18376 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018377}
18378
Takashi Iwai343a04b2011-07-06 14:28:39 +020018379#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
18380 alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai97aaab72011-07-06 14:02:55 +020018381
18382/* create a mute-switch for the given mixer widget;
18383 * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
18384 */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018385static int alc_auto_add_sw_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +020018386 const char *pfx, int cidx,
18387 hda_nid_t nid, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018388{
Takashi Iwai97aaab72011-07-06 14:02:55 +020018389 int type;
18390 unsigned long val;
18391 if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
18392 type = ALC_CTL_WIDGET_MUTE;
18393 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
18394 } else {
18395 type = ALC_CTL_BIND_MUTE;
18396 val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
18397 }
18398 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018399}
18400
Takashi Iwai343a04b2011-07-06 14:28:39 +020018401#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid) \
18402 alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018403
18404/* add playback controls from the parsed DAC table */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018405static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018406 const struct auto_pin_cfg *cfg)
18407{
18408 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018409 hda_nid_t nid, mix, pin;
18410 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018411
Takashi Iwaice764ab2011-04-27 16:35:23 +020018412 noutputs = cfg->line_outs;
18413 if (spec->multi_ios > 0)
18414 noutputs += spec->multi_ios;
18415
18416 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020018417 const char *name;
18418 int index;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018419 nid = spec->multiout.dac_nids[i];
18420 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018421 continue;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018422 if (i >= cfg->line_outs)
18423 pin = spec->multi_io[i - 1].pin;
18424 else
18425 pin = cfg->line_out_pins[i];
18426 mix = alc_auto_dac_to_mix(codec, pin, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018427 if (!mix)
18428 continue;
Takashi Iwai6843ca12011-06-24 11:03:58 +020018429 name = alc_get_line_out_pfx(spec, i, true, &index);
18430 if (!name) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018431 /* Center/LFE */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018432 err = alc_auto_add_vol_ctl(codec, "Center", 0, nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018433 if (err < 0)
18434 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018435 err = alc_auto_add_vol_ctl(codec, "LFE", 0, nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018436 if (err < 0)
18437 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018438 err = alc_auto_add_sw_ctl(codec, "Center", 0, mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018439 if (err < 0)
18440 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018441 err = alc_auto_add_sw_ctl(codec, "LFE", 0, mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018442 if (err < 0)
18443 return err;
18444 } else {
Takashi Iwai343a04b2011-07-06 14:28:39 +020018445 err = alc_auto_add_stereo_vol(codec, name, index, nid);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018446 if (err < 0)
18447 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018448 err = alc_auto_add_stereo_sw(codec, name, index, mix);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018449 if (err < 0)
18450 return err;
18451 }
18452 }
18453 return 0;
18454}
18455
18456/* add playback controls for speaker and HP outputs */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018457static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018458 hda_nid_t dac, const char *pfx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018459{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018460 struct alc_spec *spec = codec->spec;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018461 hda_nid_t mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018462 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018463
18464 if (!pin)
18465 return 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018466 if (!dac) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018467 /* the corresponding DAC is already occupied */
18468 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18469 return 0; /* no way */
18470 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018471 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018472 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18473 }
18474
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018475 mix = alc_auto_dac_to_mix(codec, pin, dac);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018476 if (!mix)
18477 return 0;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018478 err = alc_auto_add_stereo_vol(codec, pfx, 0, dac);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018479 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018480 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018481 err = alc_auto_add_stereo_sw(codec, pfx, 0, mix);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018482 if (err < 0)
18483 return err;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018484 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018485}
18486
Takashi Iwai343a04b2011-07-06 14:28:39 +020018487static int alc_auto_create_hp_out(struct hda_codec *codec)
18488{
18489 struct alc_spec *spec = codec->spec;
18490 return alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
18491 spec->multiout.hp_nid,
18492 "Headphone");
18493}
18494
18495static int alc_auto_create_speaker_out(struct hda_codec *codec)
18496{
18497 struct alc_spec *spec = codec->spec;
18498 return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0],
18499 spec->multiout.extra_out_nid[0],
18500 "Speaker");
18501}
18502
Takashi Iwai343a04b2011-07-06 14:28:39 +020018503static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018504 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018505 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018506{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018507 int i, num;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018508 hda_nid_t mix = 0;
Takashi Iwaice503f32010-07-30 10:37:29 +020018509 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018510
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018511 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaicd511552011-07-06 13:10:42 +020018512 nid = alc_go_down_to_selector(codec, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018513 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018514 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018515 if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018516 continue;
Takashi Iwaicd511552011-07-06 13:10:42 +020018517 mix = srcs[i];
18518 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018519 }
Takashi Iwaicd511552011-07-06 13:10:42 +020018520 if (!mix)
18521 return;
18522
18523 /* need the manual connection? */
18524 if (num > 1)
18525 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18526 /* unmute mixer widget inputs */
18527 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18528 AMP_IN_UNMUTE(0));
18529 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18530 AMP_IN_UNMUTE(1));
18531 /* initialize volume */
18532 if (query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
18533 nid = dac;
18534 else if (query_amp_caps(codec, mix, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
18535 nid = mix;
18536 else
18537 return;
18538 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18539 AMP_OUT_ZERO);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018540}
18541
Takashi Iwai343a04b2011-07-06 14:28:39 +020018542static void alc_auto_init_multi_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018543{
18544 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018545 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018546 int i;
18547
18548 for (i = 0; i <= HDA_SIDE; i++) {
18549 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18550 if (nid)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018551 alc_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018552 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018553 }
18554}
18555
Takashi Iwai343a04b2011-07-06 14:28:39 +020018556static void alc_auto_init_extra_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018557{
18558 struct alc_spec *spec = codec->spec;
18559 hda_nid_t pin;
18560
18561 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018562 if (pin)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018563 alc_auto_set_output_and_unmute(codec, pin, PIN_HP,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018564 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018565 pin = spec->autocfg.speaker_pins[0];
18566 if (pin)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018567 alc_auto_set_output_and_unmute(codec, pin, PIN_OUT,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018568 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018569}
18570
Takashi Iwaice764ab2011-04-27 16:35:23 +020018571/*
18572 * multi-io helper
18573 */
18574static int alc_auto_fill_multi_ios(struct hda_codec *codec,
18575 unsigned int location)
18576{
18577 struct alc_spec *spec = codec->spec;
18578 struct auto_pin_cfg *cfg = &spec->autocfg;
18579 int type, i, num_pins = 0;
18580
18581 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
18582 for (i = 0; i < cfg->num_inputs; i++) {
18583 hda_nid_t nid = cfg->inputs[i].pin;
18584 hda_nid_t dac;
18585 unsigned int defcfg, caps;
18586 if (cfg->inputs[i].type != type)
18587 continue;
18588 defcfg = snd_hda_codec_get_pincfg(codec, nid);
18589 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
18590 continue;
18591 if (location && get_defcfg_location(defcfg) != location)
18592 continue;
18593 caps = snd_hda_query_pin_caps(codec, nid);
18594 if (!(caps & AC_PINCAP_OUT))
18595 continue;
18596 dac = alc_auto_look_for_dac(codec, nid);
18597 if (!dac)
18598 continue;
18599 spec->multi_io[num_pins].pin = nid;
18600 spec->multi_io[num_pins].dac = dac;
18601 num_pins++;
Takashi Iwaidda14412011-05-02 11:29:30 +020018602 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018603 }
18604 }
18605 spec->multiout.num_dacs = 1;
18606 if (num_pins < 2)
18607 return 0;
18608 return num_pins;
18609}
18610
18611static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
18612 struct snd_ctl_elem_info *uinfo)
18613{
18614 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18615 struct alc_spec *spec = codec->spec;
18616
18617 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
18618 uinfo->count = 1;
18619 uinfo->value.enumerated.items = spec->multi_ios + 1;
18620 if (uinfo->value.enumerated.item > spec->multi_ios)
18621 uinfo->value.enumerated.item = spec->multi_ios;
18622 sprintf(uinfo->value.enumerated.name, "%dch",
18623 (uinfo->value.enumerated.item + 1) * 2);
18624 return 0;
18625}
18626
18627static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
18628 struct snd_ctl_elem_value *ucontrol)
18629{
18630 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18631 struct alc_spec *spec = codec->spec;
18632 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
18633 return 0;
18634}
18635
18636static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
18637{
18638 struct alc_spec *spec = codec->spec;
18639 hda_nid_t nid = spec->multi_io[idx].pin;
18640
18641 if (!spec->multi_io[idx].ctl_in)
18642 spec->multi_io[idx].ctl_in =
18643 snd_hda_codec_read(codec, nid, 0,
18644 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
18645 if (output) {
18646 snd_hda_codec_update_cache(codec, nid, 0,
18647 AC_VERB_SET_PIN_WIDGET_CONTROL,
18648 PIN_OUT);
18649 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
18650 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
18651 HDA_AMP_MUTE, 0);
18652 alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
18653 } else {
18654 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
18655 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
18656 HDA_AMP_MUTE, HDA_AMP_MUTE);
18657 snd_hda_codec_update_cache(codec, nid, 0,
18658 AC_VERB_SET_PIN_WIDGET_CONTROL,
18659 spec->multi_io[idx].ctl_in);
18660 }
18661 return 0;
18662}
18663
18664static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
18665 struct snd_ctl_elem_value *ucontrol)
18666{
18667 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18668 struct alc_spec *spec = codec->spec;
18669 int i, ch;
18670
18671 ch = ucontrol->value.enumerated.item[0];
18672 if (ch < 0 || ch > spec->multi_ios)
18673 return -EINVAL;
18674 if (ch == (spec->ext_channel_count - 1) / 2)
18675 return 0;
18676 spec->ext_channel_count = (ch + 1) * 2;
18677 for (i = 0; i < spec->multi_ios; i++)
18678 alc_set_multi_io(codec, i, i < ch);
18679 spec->multiout.max_channels = spec->ext_channel_count;
18680 return 1;
18681}
18682
Takashi Iwaia9111322011-05-02 11:30:18 +020018683static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +020018684 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
18685 .name = "Channel Mode",
18686 .info = alc_auto_ch_mode_info,
18687 .get = alc_auto_ch_mode_get,
18688 .put = alc_auto_ch_mode_put,
18689};
18690
Takashi Iwaicb053a82011-06-27 11:32:07 +020018691static int alc_auto_add_multi_channel_mode(struct hda_codec *codec,
18692 int (*fill_dac)(struct hda_codec *))
Takashi Iwaice764ab2011-04-27 16:35:23 +020018693{
18694 struct alc_spec *spec = codec->spec;
18695 struct auto_pin_cfg *cfg = &spec->autocfg;
18696 unsigned int location, defcfg;
18697 int num_pins;
18698
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018699 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) {
18700 /* use HP as primary out */
18701 cfg->speaker_outs = cfg->line_outs;
18702 memcpy(cfg->speaker_pins, cfg->line_out_pins,
18703 sizeof(cfg->speaker_pins));
18704 cfg->line_outs = cfg->hp_outs;
18705 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
18706 cfg->hp_outs = 0;
18707 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
18708 cfg->line_out_type = AUTO_PIN_HP_OUT;
Takashi Iwaicb053a82011-06-27 11:32:07 +020018709 if (fill_dac)
18710 fill_dac(codec);
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018711 }
Takashi Iwaice764ab2011-04-27 16:35:23 +020018712 if (cfg->line_outs != 1 ||
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018713 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
Takashi Iwaice764ab2011-04-27 16:35:23 +020018714 return 0;
18715
18716 defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
18717 location = get_defcfg_location(defcfg);
18718
18719 num_pins = alc_auto_fill_multi_ios(codec, location);
18720 if (num_pins > 0) {
18721 struct snd_kcontrol_new *knew;
18722
18723 knew = alc_kcontrol_new(spec);
18724 if (!knew)
18725 return -ENOMEM;
18726 *knew = alc_auto_channel_mode_enum;
18727 knew->name = kstrdup("Channel Mode", GFP_KERNEL);
18728 if (!knew->name)
18729 return -ENOMEM;
18730
18731 spec->multi_ios = num_pins;
18732 spec->ext_channel_count = 2;
18733 spec->multiout.num_dacs = num_pins + 1;
18734 }
18735 return 0;
18736}
18737
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018738static int alc662_parse_auto_config(struct hda_codec *codec)
18739{
18740 struct alc_spec *spec = codec->spec;
18741 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020018742 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018743
18744 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18745 alc662_ignore);
18746 if (err < 0)
18747 return err;
18748 if (!spec->autocfg.line_outs)
18749 return 0; /* can't find valid BIOS pin config */
18750
Takashi Iwai343a04b2011-07-06 14:28:39 +020018751 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018752 if (err < 0)
18753 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018754 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020018755 if (err < 0)
18756 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018757 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018758 if (err < 0)
18759 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018760 err = alc_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018761 spec->autocfg.speaker_pins[0],
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018762 spec->multiout.extra_out_nid[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018763 "Speaker");
18764 if (err < 0)
18765 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018766 err = alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018767 spec->multiout.hp_nid,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018768 "Headphone");
18769 if (err < 0)
18770 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020018771 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018772 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018773 return err;
18774
18775 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18776
Takashi Iwai757899a2010-07-30 10:48:14 +020018777 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018778
Takashi Iwai603c4012008-07-30 15:01:44 +020018779 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018780 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018781
18782 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018783 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018784
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020018785 if (!spec->dual_adc_switch)
18786 alc_remove_invalid_adc_nids(codec);
18787
Takashi Iwaiee979a142008-09-02 15:42:20 +020018788 err = alc_auto_add_mic_boost(codec);
18789 if (err < 0)
18790 return err;
18791
Kailang Yang6227cdc2010-02-25 08:36:52 +010018792 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18793 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18794 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18795 else
18796 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018797
Takashi Iwai8c872862007-06-19 12:11:16 +020018798 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018799}
18800
18801/* additional initialization for auto-configuration model */
18802static void alc662_auto_init(struct hda_codec *codec)
18803{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018804 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018805 alc_auto_init_multi_out(codec);
18806 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020018807 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020018808 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020018809 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018810 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018811 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018812}
18813
Todd Broch6be79482010-12-07 16:51:05 -080018814static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018815 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010018816{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018817 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010018818 return;
Todd Broch6be79482010-12-07 16:51:05 -080018819 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
18820 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
18821 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
18822 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
18823 (0 << AC_AMPCAP_MUTE_SHIFT)))
18824 printk(KERN_WARNING
18825 "hda_codec: failed to override amp caps for NID 0x2\n");
18826}
18827
David Henningsson6cb3b702010-09-09 08:51:44 +020018828enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040018829 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020018830 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080018831 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +010018832 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +020018833 ALC662_FIXUP_SKU_IGNORE,
David Henningsson6cb3b702010-09-09 08:51:44 +020018834};
18835
18836static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040018837 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018838 .type = ALC_FIXUP_PINS,
18839 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -040018840 { 0x15, 0x99130112 }, /* subwoofer */
18841 { }
18842 }
18843 },
David Henningsson6cb3b702010-09-09 08:51:44 +020018844 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018845 .type = ALC_FIXUP_PINS,
18846 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +020018847 { 0x17, 0x99130112 }, /* subwoofer */
18848 { }
18849 }
18850 },
Todd Broch6be79482010-12-07 16:51:05 -080018851 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018852 .type = ALC_FIXUP_FUNC,
18853 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +010018854 },
18855 [ALC662_FIXUP_CZC_P10T] = {
18856 .type = ALC_FIXUP_VERBS,
18857 .v.verbs = (const struct hda_verb[]) {
18858 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
18859 {}
18860 }
18861 },
David Henningsson94024cd2011-04-29 14:10:55 +020018862 [ALC662_FIXUP_SKU_IGNORE] = {
18863 .type = ALC_FIXUP_SKU,
18864 .v.sku = ALC_FIXUP_SKU_IGNORE,
Takashi Iwaic6b35872011-03-28 12:05:31 +020018865 },
David Henningsson6cb3b702010-09-09 08:51:44 +020018866};
18867
Takashi Iwaia9111322011-05-02 11:30:18 +020018868static const struct snd_pci_quirk alc662_fixup_tbl[] = {
David Henningssona6c47a82011-02-10 15:39:19 +010018869 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +020018870 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Daniel T Chen2df03512010-10-10 22:39:28 -040018871 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050018872 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060018873 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020018874 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +010018875 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
David Henningsson6cb3b702010-09-09 08:51:44 +020018876 {}
18877};
18878
Todd Broch6be79482010-12-07 16:51:05 -080018879static const struct alc_model_fixup alc662_fixup_models[] = {
18880 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
18881 {}
18882};
David Henningsson6cb3b702010-09-09 08:51:44 +020018883
18884
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018885static int patch_alc662(struct hda_codec *codec)
18886{
18887 struct alc_spec *spec;
18888 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020018889 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018890
18891 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18892 if (!spec)
18893 return -ENOMEM;
18894
18895 codec->spec = spec;
18896
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020018897 spec->mixer_nid = 0x0b;
18898
Kailang Yangda00c242010-03-19 11:23:45 +010018899 alc_auto_parse_customize_define(codec);
18900
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018901 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18902
Kailang Yang693194f2010-10-21 08:51:48 +020018903 coef = alc_read_coef_idx(codec, 0);
18904 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010018905 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020018906 else if (coef & (1 << 14) &&
18907 codec->bus->pci->subsystem_vendor == 0x1025 &&
18908 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010018909 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020018910 else if (coef == 0x4011)
18911 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010018912
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018913 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18914 alc662_models,
18915 alc662_cfg_tbl);
18916 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018917 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18918 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018919 board_config = ALC662_AUTO;
18920 }
18921
18922 if (board_config == ALC662_AUTO) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018923 alc_pick_fixup(codec, alc662_fixup_models,
18924 alc662_fixup_tbl, alc662_fixups);
18925 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018926 /* automatic parse from the BIOS config */
18927 err = alc662_parse_auto_config(codec);
18928 if (err < 0) {
18929 alc_free(codec);
18930 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018931 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018932 printk(KERN_INFO
18933 "hda_codec: Cannot set up configuration "
18934 "from BIOS. Using base mode...\n");
18935 board_config = ALC662_3ST_2ch_DIG;
18936 }
18937 }
18938
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018939 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020018940 err = snd_hda_attach_beep_device(codec, 0x1);
18941 if (err < 0) {
18942 alc_free(codec);
18943 return err;
18944 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018945 }
18946
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018947 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018948 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018949
Takashi Iwaidd704692009-08-11 08:45:11 +020018950 if (!spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020018951 alc_auto_fill_adc_caps(codec);
18952 alc_remove_invalid_adc_nids(codec);
Takashi Iwaidd704692009-08-11 08:45:11 +020018953 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018954
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018955 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018956 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018957
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018958 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010018959 switch (codec->vendor_id) {
18960 case 0x10ec0662:
18961 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18962 break;
18963 case 0x10ec0272:
18964 case 0x10ec0663:
18965 case 0x10ec0665:
18966 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18967 break;
18968 case 0x10ec0273:
18969 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18970 break;
18971 }
Kailang Yangcec27c82010-02-04 14:18:18 +010018972 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018973 spec->vmaster_nid = 0x02;
18974
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018975 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
18976
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018977 codec->patch_ops = alc_patch_ops;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018978 if (board_config == ALC662_AUTO)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018979 spec->init_hook = alc662_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020018980 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +020018981
Kailang Yangbf1b0222010-10-21 08:49:56 +020018982 alc_init_jacks(codec);
18983
Takashi Iwaicb53c622007-08-10 17:21:45 +020018984#ifdef CONFIG_SND_HDA_POWER_SAVE
18985 if (!spec->loopback.amplist)
18986 spec->loopback.amplist = alc662_loopbacks;
18987#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018988
18989 return 0;
18990}
18991
Kailang Yang274693f2009-12-03 10:07:50 +010018992static int patch_alc888(struct hda_codec *codec)
18993{
18994 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18995 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010018996 if (codec->vendor_id == 0x10ec0887)
18997 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
18998 else
18999 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019000 if (!codec->chip_name) {
19001 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019002 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019003 }
19004 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019005 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019006 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019007}
19008
Kailang Yangb478b992011-05-18 11:51:15 +020019009static int patch_alc899(struct hda_codec *codec)
19010{
19011 if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
19012 kfree(codec->chip_name);
19013 codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
19014 }
19015 return patch_alc882(codec);
19016}
19017
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019018/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019019 * ALC680 support
19020 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019021#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019022#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19023#define alc680_modes alc260_modes
19024
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019025static const hda_nid_t alc680_dac_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019026 /* Lout1, Lout2, hp */
19027 0x02, 0x03, 0x04
19028};
19029
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019030static const hda_nid_t alc680_adc_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019031 /* ADC0-2 */
19032 /* DMIC, MIC, Line-in*/
19033 0x07, 0x08, 0x09
19034};
19035
Kailang Yangc69aefa2010-08-17 10:39:22 +020019036/*
19037 * Analog capture ADC cgange
19038 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019039static void alc680_rec_autoswitch(struct hda_codec *codec)
19040{
19041 struct alc_spec *spec = codec->spec;
19042 struct auto_pin_cfg *cfg = &spec->autocfg;
19043 int pin_found = 0;
19044 int type_found = AUTO_PIN_LAST;
19045 hda_nid_t nid;
19046 int i;
19047
19048 for (i = 0; i < cfg->num_inputs; i++) {
19049 nid = cfg->inputs[i].pin;
Takashi Iwai06dec222011-05-17 10:00:16 +020019050 if (!is_jack_detectable(codec, nid))
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019051 continue;
19052 if (snd_hda_jack_detect(codec, nid)) {
19053 if (cfg->inputs[i].type < type_found) {
19054 type_found = cfg->inputs[i].type;
19055 pin_found = nid;
19056 }
19057 }
19058 }
19059
19060 nid = 0x07;
19061 if (pin_found)
19062 snd_hda_get_connections(codec, pin_found, &nid, 1);
19063
19064 if (nid != spec->cur_adc)
19065 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19066 spec->cur_adc = nid;
19067 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19068 spec->cur_adc_format);
19069}
19070
Kailang Yangc69aefa2010-08-17 10:39:22 +020019071static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19072 struct hda_codec *codec,
19073 unsigned int stream_tag,
19074 unsigned int format,
19075 struct snd_pcm_substream *substream)
19076{
19077 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019078
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019079 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019080 spec->cur_adc_stream_tag = stream_tag;
19081 spec->cur_adc_format = format;
19082
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019083 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019084 return 0;
19085}
19086
19087static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19088 struct hda_codec *codec,
19089 struct snd_pcm_substream *substream)
19090{
19091 snd_hda_codec_cleanup_stream(codec, 0x07);
19092 snd_hda_codec_cleanup_stream(codec, 0x08);
19093 snd_hda_codec_cleanup_stream(codec, 0x09);
19094 return 0;
19095}
19096
Takashi Iwaia9111322011-05-02 11:30:18 +020019097static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019098 .substreams = 1, /* can be overridden */
19099 .channels_min = 2,
19100 .channels_max = 2,
19101 /* NID is set in alc_build_pcms */
19102 .ops = {
19103 .prepare = alc680_capture_pcm_prepare,
19104 .cleanup = alc680_capture_pcm_cleanup
19105 },
19106};
19107
Takashi Iwaia9111322011-05-02 11:30:18 +020019108static const struct snd_kcontrol_new alc680_base_mixer[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019109 /* output mixer control */
19110 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19111 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19112 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19113 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019114 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19115 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19116 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019117 { }
19118};
19119
Takashi Iwaia9111322011-05-02 11:30:18 +020019120static const struct hda_bind_ctls alc680_bind_cap_vol = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019121 .ops = &snd_hda_bind_vol,
19122 .values = {
19123 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19124 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19125 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19126 0
19127 },
19128};
19129
Takashi Iwaia9111322011-05-02 11:30:18 +020019130static const struct hda_bind_ctls alc680_bind_cap_switch = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019131 .ops = &snd_hda_bind_sw,
19132 .values = {
19133 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19134 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19135 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19136 0
19137 },
19138};
19139
Takashi Iwaia9111322011-05-02 11:30:18 +020019140static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019141 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19142 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019143 { } /* end */
19144};
19145
19146/*
19147 * generic initialization of ADC, input mixers and output mixers
19148 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019149static const struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019150 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19151 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19152 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019153
Kailang Yangc69aefa2010-08-17 10:39:22 +020019154 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19155 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19156 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19157 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19158 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19159 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019160
19161 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19162 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19163 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19164 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19165 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019166
19167 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19168 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019169 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019170
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019171 { }
19172};
19173
Kailang Yangc69aefa2010-08-17 10:39:22 +020019174/* toggle speaker-output according to the hp-jack state */
19175static void alc680_base_setup(struct hda_codec *codec)
19176{
19177 struct alc_spec *spec = codec->spec;
19178
19179 spec->autocfg.hp_pins[0] = 0x16;
19180 spec->autocfg.speaker_pins[0] = 0x14;
19181 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019182 spec->autocfg.num_inputs = 2;
19183 spec->autocfg.inputs[0].pin = 0x18;
19184 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19185 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019186 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Takashi Iwaid922b512011-04-28 12:18:53 +020019187 spec->automute = 1;
19188 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019189}
19190
19191static void alc680_unsol_event(struct hda_codec *codec,
19192 unsigned int res)
19193{
19194 if ((res >> 26) == ALC880_HP_EVENT)
Takashi Iwaid922b512011-04-28 12:18:53 +020019195 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019196 if ((res >> 26) == ALC880_MIC_EVENT)
19197 alc680_rec_autoswitch(codec);
19198}
19199
19200static void alc680_inithook(struct hda_codec *codec)
19201{
Takashi Iwaid922b512011-04-28 12:18:53 +020019202 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019203 alc680_rec_autoswitch(codec);
19204}
19205
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019206/* create input playback/capture controls for the given pin */
19207static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19208 const char *ctlname, int idx)
19209{
19210 hda_nid_t dac;
19211 int err;
19212
19213 switch (nid) {
19214 case 0x14:
19215 dac = 0x02;
19216 break;
19217 case 0x15:
19218 dac = 0x03;
19219 break;
19220 case 0x16:
19221 dac = 0x04;
19222 break;
19223 default:
19224 return 0;
19225 }
19226 if (spec->multiout.dac_nids[0] != dac &&
19227 spec->multiout.dac_nids[1] != dac) {
19228 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19229 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19230 HDA_OUTPUT));
19231 if (err < 0)
19232 return err;
19233
19234 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19235 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19236
19237 if (err < 0)
19238 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020019239 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019240 }
19241
19242 return 0;
19243}
19244
19245/* add playback controls from the parsed DAC table */
19246static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19247 const struct auto_pin_cfg *cfg)
19248{
19249 hda_nid_t nid;
19250 int err;
19251
19252 spec->multiout.dac_nids = spec->private_dac_nids;
19253
19254 nid = cfg->line_out_pins[0];
19255 if (nid) {
19256 const char *name;
Takashi Iwai2e925dd2011-06-24 11:27:22 +020019257 int index;
19258 name = alc_get_line_out_pfx(spec, 0, true, &index);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019259 err = alc680_new_analog_output(spec, nid, name, 0);
19260 if (err < 0)
19261 return err;
19262 }
19263
19264 nid = cfg->speaker_pins[0];
19265 if (nid) {
19266 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19267 if (err < 0)
19268 return err;
19269 }
19270 nid = cfg->hp_pins[0];
19271 if (nid) {
19272 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19273 if (err < 0)
19274 return err;
19275 }
19276
19277 return 0;
19278}
19279
19280static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19281 hda_nid_t nid, int pin_type)
19282{
19283 alc_set_pin_output(codec, nid, pin_type);
19284}
19285
19286static void alc680_auto_init_multi_out(struct hda_codec *codec)
19287{
19288 struct alc_spec *spec = codec->spec;
19289 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19290 if (nid) {
19291 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19292 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19293 }
19294}
19295
19296static void alc680_auto_init_hp_out(struct hda_codec *codec)
19297{
19298 struct alc_spec *spec = codec->spec;
19299 hda_nid_t pin;
19300
19301 pin = spec->autocfg.hp_pins[0];
19302 if (pin)
19303 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19304 pin = spec->autocfg.speaker_pins[0];
19305 if (pin)
19306 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19307}
19308
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019309/*
19310 * BIOS auto configuration
19311 */
19312static int alc680_parse_auto_config(struct hda_codec *codec)
19313{
19314 struct alc_spec *spec = codec->spec;
19315 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019316 static const hda_nid_t alc680_ignore[] = { 0 };
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019317
19318 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19319 alc680_ignore);
19320 if (err < 0)
19321 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019322
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019323 if (!spec->autocfg.line_outs) {
19324 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19325 spec->multiout.max_channels = 2;
19326 spec->no_analog = 1;
19327 goto dig_only;
19328 }
19329 return 0; /* can't find valid BIOS pin config */
19330 }
19331 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19332 if (err < 0)
19333 return err;
19334
19335 spec->multiout.max_channels = 2;
19336
19337 dig_only:
19338 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019339 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019340 if (spec->kctls.list)
19341 add_mixer(spec, spec->kctls.list);
19342
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019343 err = alc_auto_add_mic_boost(codec);
19344 if (err < 0)
19345 return err;
19346
19347 return 1;
19348}
19349
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019350/* init callback for auto-configuration model -- overriding the default init */
19351static void alc680_auto_init(struct hda_codec *codec)
19352{
19353 struct alc_spec *spec = codec->spec;
19354 alc680_auto_init_multi_out(codec);
19355 alc680_auto_init_hp_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020019356 alc_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019357 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019358 if (spec->unsol_event)
19359 alc_inithook(codec);
19360}
19361
19362/*
19363 * configuration and preset
19364 */
Takashi Iwaiea734962011-01-17 11:29:34 +010019365static const char * const alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019366 [ALC680_BASE] = "base",
19367 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019368};
19369
Takashi Iwaia9111322011-05-02 11:30:18 +020019370static const struct snd_pci_quirk alc680_cfg_tbl[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019371 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19372 {}
19373};
19374
Takashi Iwaia9111322011-05-02 11:30:18 +020019375static const struct alc_config_preset alc680_presets[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019376 [ALC680_BASE] = {
19377 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020019378 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019379 .init_verbs = { alc680_init_verbs },
19380 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19381 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019382 .dig_out_nid = ALC680_DIGOUT_NID,
19383 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19384 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020019385 .unsol_event = alc680_unsol_event,
19386 .setup = alc680_base_setup,
19387 .init_hook = alc680_inithook,
19388
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019389 },
19390};
19391
19392static int patch_alc680(struct hda_codec *codec)
19393{
19394 struct alc_spec *spec;
19395 int board_config;
19396 int err;
19397
19398 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19399 if (spec == NULL)
19400 return -ENOMEM;
19401
19402 codec->spec = spec;
19403
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020019404 /* ALC680 has no aa-loopback mixer */
19405
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019406 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19407 alc680_models,
19408 alc680_cfg_tbl);
19409
19410 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19411 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19412 codec->chip_name);
19413 board_config = ALC680_AUTO;
19414 }
19415
19416 if (board_config == ALC680_AUTO) {
19417 /* automatic parse from the BIOS config */
19418 err = alc680_parse_auto_config(codec);
19419 if (err < 0) {
19420 alc_free(codec);
19421 return err;
19422 } else if (!err) {
19423 printk(KERN_INFO
19424 "hda_codec: Cannot set up configuration "
19425 "from BIOS. Using base mode...\n");
19426 board_config = ALC680_BASE;
19427 }
19428 }
19429
19430 if (board_config != ALC680_AUTO)
19431 setup_preset(codec, &alc680_presets[board_config]);
19432
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019433 if (!spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020019434 alc_auto_fill_adc_caps(codec);
19435 alc_remove_invalid_adc_nids(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019436 }
19437
19438 if (!spec->cap_mixer)
19439 set_capture_mixer(codec);
19440
19441 spec->vmaster_nid = 0x02;
19442
19443 codec->patch_ops = alc_patch_ops;
19444 if (board_config == ALC680_AUTO)
19445 spec->init_hook = alc680_auto_init;
19446
19447 return 0;
19448}
19449
19450/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019451 * patch entries
19452 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019453static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +020019454 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019455 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019456 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019457 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019458 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019459 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019460 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019461 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019462 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +020019463 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019464 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019465 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019466 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19467 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19468 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019469 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020019470 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019471 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19472 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019473 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019474 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019475 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019476 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019477 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019478 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019479 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019480 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019481 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019482 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019483 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019484 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010019485 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020019486 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020019487 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019488 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020019489 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019490 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Kailang Yangb478b992011-05-18 11:51:15 +020019491 { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019492 {} /* terminator */
19493};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019494
19495MODULE_ALIAS("snd-hda-codec-id:10ec*");
19496
19497MODULE_LICENSE("GPL");
19498MODULE_DESCRIPTION("Realtek HD-audio codec");
19499
19500static struct hda_codec_preset_list realtek_list = {
19501 .preset = snd_hda_preset_realtek,
19502 .owner = THIS_MODULE,
19503};
19504
19505static int __init patch_realtek_init(void)
19506{
19507 return snd_hda_add_codec_preset(&realtek_list);
19508}
19509
19510static void __exit patch_realtek_exit(void)
19511{
19512 snd_hda_delete_codec_preset(&realtek_list);
19513}
19514
19515module_init(patch_realtek_init)
19516module_exit(patch_realtek_exit)