blob: a0ed9e524d84a22d1fba08604dcaf291d3b6aa45 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
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 Woithe7cf51e482006-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 Avdoninbab282b92006-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ünther3e1647c52009-06-05 00:47:26 +0200255 ALC883_SONY_VAIO_TT,
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai1c7161532011-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 Iwaid922b512011-04-28 12:18:53 +0200408
409 /* auto-mute control */
410 int automute_mode;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200411 hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
Takashi Iwaid922b512011-04-28 12:18:53 +0200412
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200413 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200414 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100415
Takashi Iwai2134ea42008-01-10 16:53:55 +0100416 /* for virtual master */
417 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200418#ifdef CONFIG_SND_HDA_POWER_SAVE
419 struct hda_loopback_check loopback;
420#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200421
422 /* for PLL fix */
423 hda_nid_t pll_nid;
424 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100425
426 /* fix-up list */
427 int fixup_id;
428 const struct alc_fixup *fixup_list;
429 const char *fixup_name;
Takashi Iwaice764ab2011-04-27 16:35:23 +0200430
431 /* multi-io */
432 int multi_ios;
433 struct alc_multi_io multi_io[4];
Kailang Yangdf694da2005-12-05 19:42:22 +0100434};
435
436/*
437 * configuration template - to be copied to the spec instance
438 */
439struct alc_config_preset {
Takashi Iwaia9111322011-05-02 11:30:18 +0200440 const struct snd_kcontrol_new *mixers[5]; /* should be identical size
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200441 * with spec
442 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200443 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100444 const struct hda_verb *init_verbs[5];
445 unsigned int num_dacs;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200446 const hda_nid_t *dac_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100447 hda_nid_t dig_out_nid; /* optional */
448 hda_nid_t hp_nid; /* optional */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200449 const hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100450 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200451 const hda_nid_t *adc_nids;
452 const hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100453 hda_nid_t dig_in_nid;
454 unsigned int num_channel_mode;
455 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200456 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200457 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200458 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100459 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100460 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200461 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100462 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200463#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +0200464 const struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500465 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200466#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467};
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470/*
471 * input MUX handling
472 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200473static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
474 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
476 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
477 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200478 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
479 if (mux_idx >= spec->num_mux_defs)
480 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100481 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
482 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200483 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
485
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200486static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
487 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
489 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
490 struct alc_spec *spec = codec->spec;
491 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
492
493 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
494 return 0;
495}
496
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200497static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
498 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499{
500 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
501 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100502 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100504 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100505 hda_nid_t nid = spec->capsrc_nids ?
506 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200507 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Takashi Iwaicd896c32008-11-18 12:36:33 +0100509 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
510 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100511 if (!imux->num_items && mux_idx > 0)
512 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100513
Takashi Iwaia22d5432009-07-27 12:54:26 +0200514 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200515 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100516 /* Matrix-mixer style (e.g. ALC882) */
517 unsigned int *cur_val = &spec->cur_mux[adc_idx];
518 unsigned int i, idx;
519
520 idx = ucontrol->value.enumerated.item[0];
521 if (idx >= imux->num_items)
522 idx = imux->num_items - 1;
523 if (*cur_val == idx)
524 return 0;
525 for (i = 0; i < imux->num_items; i++) {
526 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
527 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
528 imux->items[i].index,
529 HDA_AMP_MUTE, v);
530 }
531 *cur_val = idx;
532 return 1;
533 } else {
534 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100535 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100536 &spec->cur_mux[adc_idx]);
537 }
538}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540/*
541 * channel mode setting
542 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200543static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
546 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
547 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100548 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
549 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550}
551
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200552static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
553 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554{
555 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
556 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100557 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200558 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200559 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560}
561
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200562static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
563 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
566 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200567 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
568 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200569 &spec->ext_channel_count);
570 if (err >= 0 && !spec->const_channel_count) {
571 spec->multiout.max_channels = spec->ext_channel_count;
572 if (spec->need_dac_fix)
573 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
574 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200575 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576}
577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100579 * Control the mode of pin widget settings via the mixer. "pc" is used
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300580 * instead of "%" to avoid consequences of accidentally treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100581 * being part of a format specifier. Maximum allowed length of a value is
582 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100583 *
584 * Note: some retasking pin complexes seem to ignore requests for input
585 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
586 * are requested. Therefore order this list so that this behaviour will not
587 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200588 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
589 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200590 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200591static const char * const alc_pin_mode_names[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100592 "Mic 50pc bias", "Mic 80pc bias",
593 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100594};
Takashi Iwaia9111322011-05-02 11:30:18 +0200595static const unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +0100596 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100597};
598/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200599 * in the pin being assumed to be exclusively an input or an output pin. In
600 * addition, "input" pins may or may not process the mic bias option
601 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
602 * accept requests for bias as of chip versions up to March 2006) and/or
603 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100604 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200605#define ALC_PIN_DIR_IN 0x00
606#define ALC_PIN_DIR_OUT 0x01
607#define ALC_PIN_DIR_INOUT 0x02
608#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
609#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100610
Kailang Yangea1fb292008-08-26 12:58:38 +0200611/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100612 * For each direction the minimum and maximum values are given.
613 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200614static const signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100615 { 0, 2 }, /* ALC_PIN_DIR_IN */
616 { 3, 4 }, /* ALC_PIN_DIR_OUT */
617 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200618 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
619 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100620};
621#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
622#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
623#define alc_pin_mode_n_items(_dir) \
624 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
625
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200626static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
627 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200628{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100629 unsigned int item_num = uinfo->value.enumerated.item;
630 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
631
632 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200633 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100634 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
635
636 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
637 item_num = alc_pin_mode_min(dir);
638 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200639 return 0;
640}
641
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200642static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
643 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200644{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100645 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200646 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
647 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100648 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200649 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200650 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
651 AC_VERB_GET_PIN_WIDGET_CONTROL,
652 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200653
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100654 /* Find enumerated value for current pinctl setting */
655 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2ca2009-08-02 13:30:45 +0200656 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100657 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200658 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100659 return 0;
660}
661
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200662static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
663 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100664{
665 signed int change;
666 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
667 hda_nid_t nid = kcontrol->private_value & 0xffff;
668 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
669 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200670 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
671 AC_VERB_GET_PIN_WIDGET_CONTROL,
672 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100673
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200674 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100675 val = alc_pin_mode_min(dir);
676
677 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100678 if (change) {
679 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200680 snd_hda_codec_write_cache(codec, nid, 0,
681 AC_VERB_SET_PIN_WIDGET_CONTROL,
682 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100683
Kailang Yangea1fb292008-08-26 12:58:38 +0200684 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100685 * for the requested pin mode. Enum values of 2 or less are
686 * input modes.
687 *
688 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200689 * reduces noise slightly (particularly on input) so we'll
690 * do it. However, having both input and output buffers
691 * enabled simultaneously doesn't seem to be problematic if
692 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100693 */
694 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200695 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
696 HDA_AMP_MUTE, HDA_AMP_MUTE);
697 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
698 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100699 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200700 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
701 HDA_AMP_MUTE, HDA_AMP_MUTE);
702 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
703 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100704 }
705 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200706 return change;
707}
708
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100709#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200710 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100711 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100712 .info = alc_pin_mode_info, \
713 .get = alc_pin_mode_get, \
714 .put = alc_pin_mode_put, \
715 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100716
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100717/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
718 * together using a mask with more than one bit set. This control is
719 * currently used only by the ALC260 test model. At this stage they are not
720 * needed for any "production" models.
721 */
722#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200723#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200724
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200725static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
726 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100727{
728 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
729 hda_nid_t nid = kcontrol->private_value & 0xffff;
730 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
731 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200732 unsigned int val = snd_hda_codec_read(codec, nid, 0,
733 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100734
735 *valp = (val & mask) != 0;
736 return 0;
737}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200738static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
739 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100740{
741 signed int change;
742 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
743 hda_nid_t nid = kcontrol->private_value & 0xffff;
744 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
745 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200746 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
747 AC_VERB_GET_GPIO_DATA,
748 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100749
750 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200751 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
752 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100753 gpio_data &= ~mask;
754 else
755 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200756 snd_hda_codec_write_cache(codec, nid, 0,
757 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100758
759 return change;
760}
761#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
762 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100763 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100764 .info = alc_gpio_data_info, \
765 .get = alc_gpio_data_get, \
766 .put = alc_gpio_data_put, \
767 .private_value = nid | (mask<<16) }
768#endif /* CONFIG_SND_DEBUG */
769
Jonathan Woithe92621f12006-02-28 11:47:47 +0100770/* A switch control to allow the enabling of the digital IO pins on the
771 * ALC260. This is incredibly simplistic; the intention of this control is
772 * to provide something in the test model allowing digital outputs to be
773 * identified if present. If models are found which can utilise these
774 * outputs a more complete mixer control can be devised for those models if
775 * necessary.
776 */
777#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200778#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200779
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200780static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
781 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100782{
783 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
784 hda_nid_t nid = kcontrol->private_value & 0xffff;
785 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
786 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200787 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100788 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100789
790 *valp = (val & mask) != 0;
791 return 0;
792}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200793static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
794 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100795{
796 signed int change;
797 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
798 hda_nid_t nid = kcontrol->private_value & 0xffff;
799 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
800 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200801 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100802 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200803 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100804
805 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200806 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100807 if (val==0)
808 ctrl_data &= ~mask;
809 else
810 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200811 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
812 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100813
814 return change;
815}
816#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
817 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100818 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100819 .info = alc_spdif_ctrl_info, \
820 .get = alc_spdif_ctrl_get, \
821 .put = alc_spdif_ctrl_put, \
822 .private_value = nid | (mask<<16) }
823#endif /* CONFIG_SND_DEBUG */
824
Jonathan Woithef8225f62008-01-08 12:16:54 +0100825/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
826 * Again, this is only used in the ALC26x test models to help identify when
827 * the EAPD line must be asserted for features to work.
828 */
829#ifdef CONFIG_SND_DEBUG
830#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
831
832static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
833 struct snd_ctl_elem_value *ucontrol)
834{
835 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
836 hda_nid_t nid = kcontrol->private_value & 0xffff;
837 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
838 long *valp = ucontrol->value.integer.value;
839 unsigned int val = snd_hda_codec_read(codec, nid, 0,
840 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
841
842 *valp = (val & mask) != 0;
843 return 0;
844}
845
846static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
847 struct snd_ctl_elem_value *ucontrol)
848{
849 int change;
850 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
851 hda_nid_t nid = kcontrol->private_value & 0xffff;
852 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
853 long val = *ucontrol->value.integer.value;
854 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
855 AC_VERB_GET_EAPD_BTLENABLE,
856 0x00);
857
858 /* Set/unset the masked control bit(s) as needed */
859 change = (!val ? 0 : mask) != (ctrl_data & mask);
860 if (!val)
861 ctrl_data &= ~mask;
862 else
863 ctrl_data |= mask;
864 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
865 ctrl_data);
866
867 return change;
868}
869
870#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
871 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100872 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100873 .info = alc_eapd_ctrl_info, \
874 .get = alc_eapd_ctrl_get, \
875 .put = alc_eapd_ctrl_put, \
876 .private_value = nid | (mask<<16) }
877#endif /* CONFIG_SND_DEBUG */
878
Kailang Yangdf694da2005-12-05 19:42:22 +0100879/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100880 * set up the input pin config (depending on the given auto-pin type)
881 */
882static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
883 int auto_pin_type)
884{
885 unsigned int val = PIN_IN;
886
Takashi Iwai86e29592010-09-09 14:50:17 +0200887 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100888 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200889 unsigned int oldval;
890 oldval = snd_hda_codec_read(codec, nid, 0,
891 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100892 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100893 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200894 /* if the default pin setup is vref50, we give it priority */
895 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100896 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200897 else if (pincap & AC_PINCAP_VREF_50)
898 val = PIN_VREF50;
899 else if (pincap & AC_PINCAP_VREF_100)
900 val = PIN_VREF100;
901 else if (pincap & AC_PINCAP_VREF_GRD)
902 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100903 }
904 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
905}
906
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200907static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
908{
909 struct alc_spec *spec = codec->spec;
910 struct auto_pin_cfg *cfg = &spec->autocfg;
911
912 if (!cfg->line_outs) {
913 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
914 cfg->line_out_pins[cfg->line_outs])
915 cfg->line_outs++;
916 }
917 if (!cfg->speaker_outs) {
918 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
919 cfg->speaker_pins[cfg->speaker_outs])
920 cfg->speaker_outs++;
921 }
922 if (!cfg->hp_outs) {
923 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
924 cfg->hp_pins[cfg->hp_outs])
925 cfg->hp_outs++;
926 }
927}
928
Takashi Iwai23f0c042009-02-26 13:03:58 +0100929/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100930 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200931static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100932{
933 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
934 return;
935 spec->mixers[spec->num_mixers++] = mix;
936}
937
938static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
939{
940 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
941 return;
942 spec->init_verbs[spec->num_init_verbs++] = verb;
943}
944
945/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100946 * set up from the preset table
947 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200948static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200949 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100950{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200951 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100952 int i;
953
954 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100955 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100956 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200957 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
958 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100959 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200960
Kailang Yangdf694da2005-12-05 19:42:22 +0100961 spec->channel_mode = preset->channel_mode;
962 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200963 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200964 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100965
Hector Martin3b315d72009-06-02 10:54:19 +0200966 if (preset->const_channel_count)
967 spec->multiout.max_channels = preset->const_channel_count;
968 else
969 spec->multiout.max_channels = spec->channel_mode[0].channels;
970 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100971
972 spec->multiout.num_dacs = preset->num_dacs;
973 spec->multiout.dac_nids = preset->dac_nids;
974 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800975 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100976 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200977
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200978 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200979 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200980 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100981 spec->input_mux = preset->input_mux;
982
983 spec->num_adc_nids = preset->num_adc_nids;
984 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100985 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100986 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100987
988 spec->unsol_event = preset->unsol_event;
989 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200990#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100991 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200992 spec->loopback.amplist = preset->loopbacks;
993#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200994
995 if (preset->setup)
996 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200997
998 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100999}
1000
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001001/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +02001002static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001003 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1004 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1005 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1006 { }
1007};
1008
Takashi Iwaia9111322011-05-02 11:30:18 +02001009static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001010 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1011 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1012 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
1013 { }
1014};
1015
Takashi Iwaia9111322011-05-02 11:30:18 +02001016static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02001017 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
1018 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
1019 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
1020 { }
1021};
1022
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001023/*
1024 * Fix hardware PLL issue
1025 * On some codecs, the analog PLL gating control must be off while
1026 * the default value is 1.
1027 */
1028static void alc_fix_pll(struct hda_codec *codec)
1029{
1030 struct alc_spec *spec = codec->spec;
1031 unsigned int val;
1032
1033 if (!spec->pll_nid)
1034 return;
1035 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1036 spec->pll_coef_idx);
1037 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1038 AC_VERB_GET_PROC_COEF, 0);
1039 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1040 spec->pll_coef_idx);
1041 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1042 val & ~(1 << spec->pll_coef_bit));
1043}
1044
1045static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1046 unsigned int coef_idx, unsigned int coef_bit)
1047{
1048 struct alc_spec *spec = codec->spec;
1049 spec->pll_nid = nid;
1050 spec->pll_coef_idx = coef_idx;
1051 spec->pll_coef_bit = coef_bit;
1052 alc_fix_pll(codec);
1053}
1054
Kailang Yang9ad0e492010-09-14 23:22:00 +02001055static int alc_init_jacks(struct hda_codec *codec)
1056{
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001057#ifdef CONFIG_SND_HDA_INPUT_JACK
Kailang Yang9ad0e492010-09-14 23:22:00 +02001058 struct alc_spec *spec = codec->spec;
1059 int err;
1060 unsigned int hp_nid = spec->autocfg.hp_pins[0];
1061 unsigned int mic_nid = spec->ext_mic.pin;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001062 unsigned int dock_nid = spec->dock_mic.pin;
Kailang Yang9ad0e492010-09-14 23:22:00 +02001063
Takashi Iwai265a0242010-09-21 11:26:21 +02001064 if (hp_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001065 err = snd_hda_input_jack_add(codec, hp_nid,
1066 SND_JACK_HEADPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001067 if (err < 0)
1068 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001069 snd_hda_input_jack_report(codec, hp_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001070 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001071
Takashi Iwai265a0242010-09-21 11:26:21 +02001072 if (mic_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001073 err = snd_hda_input_jack_add(codec, mic_nid,
1074 SND_JACK_MICROPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001075 if (err < 0)
1076 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001077 snd_hda_input_jack_report(codec, mic_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001078 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001079 if (dock_nid) {
1080 err = snd_hda_input_jack_add(codec, dock_nid,
1081 SND_JACK_MICROPHONE, NULL);
1082 if (err < 0)
1083 return err;
1084 snd_hda_input_jack_report(codec, dock_nid);
1085 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001086#endif /* CONFIG_SND_HDA_INPUT_JACK */
Kailang Yang9ad0e492010-09-14 23:22:00 +02001087 return 0;
1088}
Kailang Yang9ad0e492010-09-14 23:22:00 +02001089
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001090static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +02001091{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001092 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +02001093
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001094 for (i = 0; i < num_pins; i++) {
1095 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001096 if (!nid)
1097 break;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001098 snd_hda_input_jack_report(codec, nid);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001099 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001100 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001101 return present;
1102}
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001103
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001104static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +02001105 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001106{
1107 struct alc_spec *spec = codec->spec;
1108 unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02001109 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001110 int i;
1111
1112 for (i = 0; i < num_pins; i++) {
1113 hda_nid_t nid = pins[i];
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001114 if (!nid)
1115 break;
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001116 switch (spec->automute_mode) {
1117 case ALC_AUTOMUTE_PIN:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001118 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001119 AC_VERB_SET_PIN_WIDGET_CONTROL,
1120 pin_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001121 break;
1122 case ALC_AUTOMUTE_AMP:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001123 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001124 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001125 break;
1126 case ALC_AUTOMUTE_MIXER:
1127 nid = spec->automute_mixer_nid[i];
1128 if (!nid)
1129 break;
1130 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001131 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001132 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001133 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001134 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001135 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001136 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001137}
1138
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001139/* Toggle internal speakers muting */
1140static void update_speakers(struct hda_codec *codec)
1141{
1142 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001143 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001144
Takashi Iwaic0a20262011-06-10 15:28:15 +02001145 /* Control HP pins/amps depending on master_mute state;
1146 * in general, HP pins/amps control should be enabled in all cases,
1147 * but currently set only for master_mute, just to be safe
1148 */
1149 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1150 spec->autocfg.hp_pins, spec->master_mute, true);
1151
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001152 if (!spec->automute)
1153 on = 0;
1154 else
1155 on = spec->jack_present | spec->line_jack_present;
1156 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001157 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001158 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001159
1160 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001161 /* if LO is a copy of either HP or Speaker, don't need to handle it */
1162 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
1163 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001164 return;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001165 if (!spec->automute_lines || !spec->automute)
1166 on = 0;
1167 else
1168 on = spec->jack_present;
1169 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001170 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001171 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001172}
1173
1174static void alc_hp_automute(struct hda_codec *codec)
1175{
1176 struct alc_spec *spec = codec->spec;
1177
1178 if (!spec->automute)
1179 return;
1180 spec->jack_present =
1181 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1182 spec->autocfg.hp_pins);
1183 update_speakers(codec);
1184}
1185
1186static void alc_line_automute(struct hda_codec *codec)
1187{
1188 struct alc_spec *spec = codec->spec;
1189
1190 if (!spec->automute || !spec->detect_line)
1191 return;
1192 spec->line_jack_present =
1193 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
1194 spec->autocfg.line_out_pins);
1195 update_speakers(codec);
1196}
1197
Takashi Iwai8d087c72011-06-28 12:45:47 +02001198#define get_connection_index(codec, mux, nid) \
1199 snd_hda_get_conn_index(codec, mux, nid, 0)
Takashi Iwai6c819492009-08-10 18:47:44 +02001200
Takashi Iwai840b64c2010-07-13 22:49:01 +02001201/* switch the current ADC according to the jack state */
1202static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1203{
1204 struct alc_spec *spec = codec->spec;
1205 unsigned int present;
1206 hda_nid_t new_adc;
1207
1208 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1209 if (present)
1210 spec->cur_adc_idx = 1;
1211 else
1212 spec->cur_adc_idx = 0;
1213 new_adc = spec->adc_nids[spec->cur_adc_idx];
1214 if (spec->cur_adc && spec->cur_adc != new_adc) {
1215 /* stream is running, let's swap the current ADC */
Takashi Iwaif0cea792010-08-13 11:56:53 +02001216 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai840b64c2010-07-13 22:49:01 +02001217 spec->cur_adc = new_adc;
1218 snd_hda_codec_setup_stream(codec, new_adc,
1219 spec->cur_adc_stream_tag, 0,
1220 spec->cur_adc_format);
1221 }
1222}
1223
Kailang Yang7fb0d782008-10-15 11:12:35 +02001224static void alc_mic_automute(struct hda_codec *codec)
1225{
1226 struct alc_spec *spec = codec->spec;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001227 struct alc_mic_route *dead1, *dead2, *alive;
Takashi Iwai6c819492009-08-10 18:47:44 +02001228 unsigned int present, type;
1229 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001230
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001231 if (!spec->auto_mic)
1232 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001233 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1234 return;
1235 if (snd_BUG_ON(!spec->adc_nids))
1236 return;
1237
Takashi Iwai840b64c2010-07-13 22:49:01 +02001238 if (spec->dual_adc_switch) {
1239 alc_dual_mic_adc_auto_switch(codec);
1240 return;
1241 }
1242
Takashi Iwai6c819492009-08-10 18:47:44 +02001243 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1244
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001245 alive = &spec->int_mic;
1246 dead1 = &spec->ext_mic;
1247 dead2 = &spec->dock_mic;
1248
Wu Fengguang864f92b2009-11-18 12:38:02 +08001249 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001250 if (present) {
1251 alive = &spec->ext_mic;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001252 dead1 = &spec->int_mic;
1253 dead2 = &spec->dock_mic;
1254 }
1255 if (!present && spec->dock_mic.pin > 0) {
1256 present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
1257 if (present) {
1258 alive = &spec->dock_mic;
1259 dead1 = &spec->int_mic;
1260 dead2 = &spec->ext_mic;
1261 }
1262 snd_hda_input_jack_report(codec, spec->dock_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001263 }
1264
Takashi Iwai6c819492009-08-10 18:47:44 +02001265 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1266 if (type == AC_WID_AUD_MIX) {
1267 /* Matrix-mixer style (e.g. ALC882) */
1268 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1269 alive->mux_idx,
1270 HDA_AMP_MUTE, 0);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001271 if (dead1->pin > 0)
1272 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1273 dead1->mux_idx,
1274 HDA_AMP_MUTE, HDA_AMP_MUTE);
1275 if (dead2->pin > 0)
1276 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1277 dead2->mux_idx,
1278 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai6c819492009-08-10 18:47:44 +02001279 } else {
1280 /* MUX style (e.g. ALC880) */
1281 snd_hda_codec_write_cache(codec, cap_nid, 0,
1282 AC_VERB_SET_CONNECT_SEL,
1283 alive->mux_idx);
1284 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001285 snd_hda_input_jack_report(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001286
1287 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001288}
1289
Kailang Yangc9b58002007-10-16 14:30:01 +02001290/* unsolicited event for HP jack sensing */
1291static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1292{
1293 if (codec->vendor_id == 0x10ec0880)
1294 res >>= 28;
1295 else
1296 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001297 switch (res) {
1298 case ALC880_HP_EVENT:
Takashi Iwaid922b512011-04-28 12:18:53 +02001299 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001300 break;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001301 case ALC880_FRONT_EVENT:
1302 alc_line_automute(codec);
1303 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001304 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001305 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001306 break;
1307 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001308}
1309
1310static void alc_inithook(struct hda_codec *codec)
1311{
Takashi Iwaid922b512011-04-28 12:18:53 +02001312 alc_hp_automute(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001313 alc_line_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001314 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001315}
1316
Kailang Yangf9423e72008-05-27 12:32:25 +02001317/* additional initialization for ALC888 variants */
1318static void alc888_coef_init(struct hda_codec *codec)
1319{
1320 unsigned int tmp;
1321
1322 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1323 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1324 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001325 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001326 /* alc888S-VC */
1327 snd_hda_codec_read(codec, 0x20, 0,
1328 AC_VERB_SET_PROC_COEF, 0x830);
1329 else
1330 /* alc888-VB */
1331 snd_hda_codec_read(codec, 0x20, 0,
1332 AC_VERB_SET_PROC_COEF, 0x3030);
1333}
1334
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001335static void alc889_coef_init(struct hda_codec *codec)
1336{
1337 unsigned int tmp;
1338
1339 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1340 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1341 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1342 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1343}
1344
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001345/* turn on/off EAPD control (only if available) */
1346static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1347{
1348 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1349 return;
1350 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1351 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1352 on ? 2 : 0);
1353}
1354
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001355/* turn on/off EAPD controls of the codec */
1356static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
1357{
1358 /* We currently only handle front, HP */
Takashi Iwai39fa84e2011-06-27 15:28:57 +02001359 static hda_nid_t pins[] = {
1360 0x0f, 0x10, 0x14, 0x15, 0
1361 };
1362 hda_nid_t *p;
1363 for (p = pins; *p; p++)
1364 set_eapd(codec, *p, on);
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001365}
1366
Takashi Iwai1c7161532011-04-07 10:37:16 +02001367/* generic shutup callback;
1368 * just turning off EPAD and a little pause for avoiding pop-noise
1369 */
1370static void alc_eapd_shutup(struct hda_codec *codec)
1371{
1372 alc_auto_setup_eapd(codec, false);
1373 msleep(200);
1374}
1375
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001376static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001377{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001378 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001379
Takashi Iwai39fa84e2011-06-27 15:28:57 +02001380 alc_auto_setup_eapd(codec, true);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001381 switch (type) {
1382 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001383 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1384 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001385 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001386 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1387 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001388 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001389 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1390 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001391 case ALC_INIT_DEFAULT:
Kailang Yangc9b58002007-10-16 14:30:01 +02001392 switch (codec->vendor_id) {
1393 case 0x10ec0260:
1394 snd_hda_codec_write(codec, 0x1a, 0,
1395 AC_VERB_SET_COEF_INDEX, 7);
1396 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1397 AC_VERB_GET_PROC_COEF, 0);
1398 snd_hda_codec_write(codec, 0x1a, 0,
1399 AC_VERB_SET_COEF_INDEX, 7);
1400 snd_hda_codec_write(codec, 0x1a, 0,
1401 AC_VERB_SET_PROC_COEF,
1402 tmp | 0x2010);
1403 break;
1404 case 0x10ec0262:
1405 case 0x10ec0880:
1406 case 0x10ec0882:
1407 case 0x10ec0883:
1408 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001409 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +01001410 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001411 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001412 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001413 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001414 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001415 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001416#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001417 case 0x10ec0267:
1418 case 0x10ec0268:
1419 snd_hda_codec_write(codec, 0x20, 0,
1420 AC_VERB_SET_COEF_INDEX, 7);
1421 tmp = snd_hda_codec_read(codec, 0x20, 0,
1422 AC_VERB_GET_PROC_COEF, 0);
1423 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001424 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001425 snd_hda_codec_write(codec, 0x20, 0,
1426 AC_VERB_SET_PROC_COEF,
1427 tmp | 0x3000);
1428 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001429#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001430 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001431 break;
1432 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001433}
Kailang Yangea1fb292008-08-26 12:58:38 +02001434
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001435static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
1436 struct snd_ctl_elem_info *uinfo)
1437{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001438 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1439 struct alc_spec *spec = codec->spec;
1440 static const char * const texts2[] = {
1441 "Disabled", "Enabled"
1442 };
1443 static const char * const texts3[] = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001444 "Disabled", "Speaker Only", "Line-Out+Speaker"
1445 };
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001446 const char * const *texts;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001447
1448 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1449 uinfo->count = 1;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001450 if (spec->automute_hp_lo) {
1451 uinfo->value.enumerated.items = 3;
1452 texts = texts3;
1453 } else {
1454 uinfo->value.enumerated.items = 2;
1455 texts = texts2;
1456 }
1457 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1458 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001459 strcpy(uinfo->value.enumerated.name,
1460 texts[uinfo->value.enumerated.item]);
1461 return 0;
1462}
1463
1464static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
1465 struct snd_ctl_elem_value *ucontrol)
1466{
1467 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1468 struct alc_spec *spec = codec->spec;
1469 unsigned int val;
1470 if (!spec->automute)
1471 val = 0;
1472 else if (!spec->automute_lines)
1473 val = 1;
1474 else
1475 val = 2;
1476 ucontrol->value.enumerated.item[0] = val;
1477 return 0;
1478}
1479
1480static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
1481 struct snd_ctl_elem_value *ucontrol)
1482{
1483 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1484 struct alc_spec *spec = codec->spec;
1485
1486 switch (ucontrol->value.enumerated.item[0]) {
1487 case 0:
1488 if (!spec->automute)
1489 return 0;
1490 spec->automute = 0;
1491 break;
1492 case 1:
1493 if (spec->automute && !spec->automute_lines)
1494 return 0;
1495 spec->automute = 1;
1496 spec->automute_lines = 0;
1497 break;
1498 case 2:
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001499 if (!spec->automute_hp_lo)
1500 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001501 if (spec->automute && spec->automute_lines)
1502 return 0;
1503 spec->automute = 1;
1504 spec->automute_lines = 1;
1505 break;
1506 default:
1507 return -EINVAL;
1508 }
1509 update_speakers(codec);
1510 return 1;
1511}
1512
Takashi Iwaia9111322011-05-02 11:30:18 +02001513static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001514 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1515 .name = "Auto-Mute Mode",
1516 .info = alc_automute_mode_info,
1517 .get = alc_automute_mode_get,
1518 .put = alc_automute_mode_put,
1519};
1520
1521static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
1522
1523static int alc_add_automute_mode_enum(struct hda_codec *codec)
1524{
1525 struct alc_spec *spec = codec->spec;
1526 struct snd_kcontrol_new *knew;
1527
1528 knew = alc_kcontrol_new(spec);
1529 if (!knew)
1530 return -ENOMEM;
1531 *knew = alc_automute_mode_enum;
1532 knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
1533 if (!knew->name)
1534 return -ENOMEM;
1535 return 0;
1536}
1537
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001538static void alc_init_auto_hp(struct hda_codec *codec)
1539{
1540 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001541 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001542 int present = 0;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001543 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001544
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001545 if (cfg->hp_pins[0])
1546 present++;
1547 if (cfg->line_out_pins[0])
1548 present++;
1549 if (cfg->speaker_pins[0])
1550 present++;
1551 if (present < 2) /* need two different output types */
1552 return;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001553 if (present == 3)
1554 spec->automute_hp_lo = 1; /* both HP and LO automute */
Kailang Yangc9b58002007-10-16 14:30:01 +02001555
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001556 if (!cfg->speaker_pins[0]) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001557 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1558 sizeof(cfg->speaker_pins));
1559 cfg->speaker_outs = cfg->line_outs;
1560 }
1561
1562 if (!cfg->hp_pins[0]) {
1563 memcpy(cfg->hp_pins, cfg->line_out_pins,
1564 sizeof(cfg->hp_pins));
1565 cfg->hp_outs = cfg->line_outs;
1566 }
1567
1568 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001569 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001570 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001571 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001572 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001573 nid);
1574 snd_hda_codec_write_cache(codec, nid, 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001575 AC_VERB_SET_UNSOLICITED_ENABLE,
1576 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaid922b512011-04-28 12:18:53 +02001577 spec->automute = 1;
1578 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001579 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001580 if (spec->automute && cfg->line_out_pins[0] &&
1581 cfg->line_out_pins[0] != cfg->hp_pins[0] &&
1582 cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
1583 for (i = 0; i < cfg->line_outs; i++) {
1584 hda_nid_t nid = cfg->line_out_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001585 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001586 continue;
1587 snd_printdd("realtek: Enable Line-Out auto-muting "
1588 "on NID 0x%x\n", nid);
1589 snd_hda_codec_write_cache(codec, nid, 0,
1590 AC_VERB_SET_UNSOLICITED_ENABLE,
1591 AC_USRSP_EN | ALC880_FRONT_EVENT);
1592 spec->detect_line = 1;
1593 }
Takashi Iwai52d3cb82011-05-17 10:04:08 +02001594 spec->automute_lines = spec->detect_line;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001595 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001596
1597 if (spec->automute) {
1598 /* create a control for automute mode */
1599 alc_add_automute_mode_enum(codec);
1600 spec->unsol_event = alc_sku_unsol_event;
1601 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001602}
1603
Takashi Iwai6c819492009-08-10 18:47:44 +02001604static void alc_init_auto_mic(struct hda_codec *codec)
1605{
1606 struct alc_spec *spec = codec->spec;
1607 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001608 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001609 int i;
1610
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001611 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001612 for (i = 0; i < cfg->num_inputs; i++) {
1613 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001614 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001615 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001616 switch (snd_hda_get_input_pin_attr(defcfg)) {
1617 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001618 if (fixed)
1619 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001620 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1621 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001622 fixed = nid;
1623 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001624 case INPUT_PIN_ATTR_UNUSED:
1625 return; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001626 case INPUT_PIN_ATTR_DOCK:
1627 if (dock)
1628 return; /* already occupied */
1629 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
1630 return; /* invalid type */
1631 dock = nid;
1632 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001633 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001634 if (ext)
1635 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001636 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1637 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001638 ext = nid;
1639 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001640 }
1641 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001642 if (!ext && dock) {
1643 ext = dock;
1644 dock = 0;
1645 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001646 if (!ext || !fixed)
1647 return;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001648 if (!is_jack_detectable(codec, ext))
Takashi Iwai6c819492009-08-10 18:47:44 +02001649 return; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001650 if (dock && !is_jack_detectable(codec, dock))
1651 return; /* no unsol support */
1652 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1653 ext, fixed, dock);
Takashi Iwai6c819492009-08-10 18:47:44 +02001654 spec->ext_mic.pin = ext;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001655 spec->dock_mic.pin = dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001656 spec->int_mic.pin = fixed;
1657 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001658 spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai6c819492009-08-10 18:47:44 +02001659 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1660 spec->auto_mic = 1;
1661 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1662 AC_VERB_SET_UNSOLICITED_ENABLE,
1663 AC_USRSP_EN | ALC880_MIC_EVENT);
1664 spec->unsol_event = alc_sku_unsol_event;
1665}
1666
David Henningsson90622912010-10-14 14:50:18 +02001667/* Could be any non-zero and even value. When used as fixup, tells
1668 * the driver to ignore any present sku defines.
1669 */
1670#define ALC_FIXUP_SKU_IGNORE (2)
1671
Kailang Yangda00c242010-03-19 11:23:45 +01001672static int alc_auto_parse_customize_define(struct hda_codec *codec)
1673{
1674 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001675 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001676 struct alc_spec *spec = codec->spec;
1677
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001678 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1679
David Henningsson90622912010-10-14 14:50:18 +02001680 if (spec->cdefine.fixup) {
1681 ass = spec->cdefine.sku_cfg;
1682 if (ass == ALC_FIXUP_SKU_IGNORE)
1683 return -1;
1684 goto do_sku;
1685 }
1686
Kailang Yangda00c242010-03-19 11:23:45 +01001687 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001688 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001689 goto do_sku;
1690
1691 nid = 0x1d;
1692 if (codec->vendor_id == 0x10ec0260)
1693 nid = 0x17;
1694 ass = snd_hda_codec_get_pincfg(codec, nid);
1695
1696 if (!(ass & 1)) {
1697 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1698 codec->chip_name, ass);
1699 return -1;
1700 }
1701
1702 /* check sum */
1703 tmp = 0;
1704 for (i = 1; i < 16; i++) {
1705 if ((ass >> i) & 1)
1706 tmp++;
1707 }
1708 if (((ass >> 16) & 0xf) != tmp)
1709 return -1;
1710
1711 spec->cdefine.port_connectivity = ass >> 30;
1712 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1713 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1714 spec->cdefine.customization = ass >> 8;
1715do_sku:
1716 spec->cdefine.sku_cfg = ass;
1717 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1718 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1719 spec->cdefine.swap = (ass & 0x2) >> 1;
1720 spec->cdefine.override = ass & 0x1;
1721
1722 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1723 nid, spec->cdefine.sku_cfg);
1724 snd_printd("SKU: port_connectivity=0x%x\n",
1725 spec->cdefine.port_connectivity);
1726 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1727 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1728 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1729 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1730 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1731 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1732 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1733
1734 return 0;
1735}
1736
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001737static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1738{
1739 int i;
1740 for (i = 0; i < nums; i++)
1741 if (list[i] == nid)
1742 return true;
1743 return false;
1744}
1745
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001746/* check subsystem ID and set up device-specific initialization;
1747 * return 1 if initialized, 0 if invalid SSID
1748 */
1749/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1750 * 31 ~ 16 : Manufacture ID
1751 * 15 ~ 8 : SKU ID
1752 * 7 ~ 0 : Assembly ID
1753 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1754 */
1755static int alc_subsystem_id(struct hda_codec *codec,
1756 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001757 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001758{
1759 unsigned int ass, tmp, i;
1760 unsigned nid;
1761 struct alc_spec *spec = codec->spec;
1762
David Henningsson90622912010-10-14 14:50:18 +02001763 if (spec->cdefine.fixup) {
1764 ass = spec->cdefine.sku_cfg;
1765 if (ass == ALC_FIXUP_SKU_IGNORE)
1766 return 0;
1767 goto do_sku;
1768 }
1769
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001770 ass = codec->subsystem_id & 0xffff;
1771 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1772 goto do_sku;
1773
1774 /* invalid SSID, check the special NID pin defcfg instead */
1775 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001776 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001777 * 29~21 : reserve
1778 * 20 : PCBEEP input
1779 * 19~16 : Check sum (15:1)
1780 * 15~1 : Custom
1781 * 0 : override
1782 */
1783 nid = 0x1d;
1784 if (codec->vendor_id == 0x10ec0260)
1785 nid = 0x17;
1786 ass = snd_hda_codec_get_pincfg(codec, nid);
1787 snd_printd("realtek: No valid SSID, "
1788 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001789 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001790 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001791 return 0;
1792 if ((ass >> 30) != 1) /* no physical connection */
1793 return 0;
1794
1795 /* check sum */
1796 tmp = 0;
1797 for (i = 1; i < 16; i++) {
1798 if ((ass >> i) & 1)
1799 tmp++;
1800 }
1801 if (((ass >> 16) & 0xf) != tmp)
1802 return 0;
1803do_sku:
1804 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1805 ass & 0xffff, codec->vendor_id);
1806 /*
1807 * 0 : override
1808 * 1 : Swap Jack
1809 * 2 : 0 --> Desktop, 1 --> Laptop
1810 * 3~5 : External Amplifier control
1811 * 7~6 : Reserved
1812 */
1813 tmp = (ass & 0x38) >> 3; /* external Amp control */
1814 switch (tmp) {
1815 case 1:
1816 spec->init_amp = ALC_INIT_GPIO1;
1817 break;
1818 case 3:
1819 spec->init_amp = ALC_INIT_GPIO2;
1820 break;
1821 case 7:
1822 spec->init_amp = ALC_INIT_GPIO3;
1823 break;
1824 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001825 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001826 spec->init_amp = ALC_INIT_DEFAULT;
1827 break;
1828 }
1829
1830 /* is laptop or Desktop and enable the function "Mute internal speaker
1831 * when the external headphone out jack is plugged"
1832 */
1833 if (!(ass & 0x8000))
1834 return 1;
1835 /*
1836 * 10~8 : Jack location
1837 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1838 * 14~13: Resvered
1839 * 15 : 1 --> enable the function "Mute internal speaker
1840 * when the external headphone out jack is plugged"
1841 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001842 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001843 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001844 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1845 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001846 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001847 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001848 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001849 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001850 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001851 else if (tmp == 3)
1852 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001853 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001854 return 1;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001855 if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
1856 spec->autocfg.line_outs))
1857 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001858 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001859 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001860 return 1;
1861}
Kailang Yangea1fb292008-08-26 12:58:38 +02001862
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001863static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001864 hda_nid_t porta, hda_nid_t porte,
1865 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001866{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001867 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001868 struct alc_spec *spec = codec->spec;
1869 snd_printd("realtek: "
1870 "Enable default setup for auto mode as fallback\n");
1871 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001872 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001873
1874 alc_init_auto_hp(codec);
1875 alc_init_auto_mic(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001876}
1877
Takashi Iwai41e41f12005-06-08 14:48:49 +02001878/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001879 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001880 */
1881
1882struct alc_pincfg {
1883 hda_nid_t nid;
1884 u32 val;
1885};
1886
Todd Broche1eb5f12010-12-06 11:19:51 -08001887struct alc_model_fixup {
1888 const int id;
1889 const char *name;
1890};
1891
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001892struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001893 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001894 bool chained;
1895 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001896 union {
1897 unsigned int sku;
1898 const struct alc_pincfg *pins;
1899 const struct hda_verb *verbs;
1900 void (*func)(struct hda_codec *codec,
1901 const struct alc_fixup *fix,
1902 int action);
1903 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001904};
1905
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001906enum {
1907 ALC_FIXUP_INVALID,
1908 ALC_FIXUP_SKU,
1909 ALC_FIXUP_PINS,
1910 ALC_FIXUP_VERBS,
1911 ALC_FIXUP_FUNC,
1912};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001913
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001914enum {
1915 ALC_FIXUP_ACT_PRE_PROBE,
1916 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001917 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001918};
1919
1920static void alc_apply_fixup(struct hda_codec *codec, int action)
1921{
1922 struct alc_spec *spec = codec->spec;
1923 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001924#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001925 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001926#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001927 int depth = 0;
1928
1929 if (!spec->fixup_list)
1930 return;
1931
1932 while (id >= 0) {
1933 const struct alc_fixup *fix = spec->fixup_list + id;
1934 const struct alc_pincfg *cfg;
1935
1936 switch (fix->type) {
1937 case ALC_FIXUP_SKU:
1938 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
1939 break;;
1940 snd_printdd(KERN_INFO "hda_codec: %s: "
1941 "Apply sku override for %s\n",
1942 codec->chip_name, modelname);
1943 spec->cdefine.sku_cfg = fix->v.sku;
1944 spec->cdefine.fixup = 1;
1945 break;
1946 case ALC_FIXUP_PINS:
1947 cfg = fix->v.pins;
1948 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1949 break;
1950 snd_printdd(KERN_INFO "hda_codec: %s: "
1951 "Apply pincfg for %s\n",
1952 codec->chip_name, modelname);
1953 for (; cfg->nid; cfg++)
1954 snd_hda_codec_set_pincfg(codec, cfg->nid,
1955 cfg->val);
1956 break;
1957 case ALC_FIXUP_VERBS:
1958 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
1959 break;
1960 snd_printdd(KERN_INFO "hda_codec: %s: "
1961 "Apply fix-verbs for %s\n",
1962 codec->chip_name, modelname);
1963 add_verb(codec->spec, fix->v.verbs);
1964 break;
1965 case ALC_FIXUP_FUNC:
1966 if (!fix->v.func)
1967 break;
1968 snd_printdd(KERN_INFO "hda_codec: %s: "
1969 "Apply fix-func for %s\n",
1970 codec->chip_name, modelname);
1971 fix->v.func(codec, fix, action);
1972 break;
1973 default:
1974 snd_printk(KERN_ERR "hda_codec: %s: "
1975 "Invalid fixup type %d\n",
1976 codec->chip_name, fix->type);
1977 break;
1978 }
Takashi Iwai24af2b12011-05-02 13:55:36 +02001979 if (!fix->chained)
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001980 break;
1981 if (++depth > 10)
1982 break;
Takashi Iwai24af2b12011-05-02 13:55:36 +02001983 id = fix->chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01001984 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001985}
1986
Todd Broche1eb5f12010-12-06 11:19:51 -08001987static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001988 const struct alc_model_fixup *models,
1989 const struct snd_pci_quirk *quirk,
1990 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08001991{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001992 struct alc_spec *spec = codec->spec;
1993 int id = -1;
1994 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08001995
Todd Broche1eb5f12010-12-06 11:19:51 -08001996 if (codec->modelname && models) {
1997 while (models->name) {
1998 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001999 id = models->id;
2000 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002001 break;
2002 }
2003 models++;
2004 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002005 }
2006 if (id < 0) {
2007 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
2008 if (quirk) {
2009 id = quirk->value;
2010#ifdef CONFIG_SND_DEBUG_VERBOSE
2011 name = quirk->name;
2012#endif
2013 }
2014 }
2015
2016 spec->fixup_id = id;
2017 if (id >= 0) {
2018 spec->fixup_list = fixlist;
2019 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002020 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002021}
2022
Kailang Yang274693f2009-12-03 10:07:50 +01002023static int alc_read_coef_idx(struct hda_codec *codec,
2024 unsigned int coef_idx)
2025{
2026 unsigned int val;
2027 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2028 coef_idx);
2029 val = snd_hda_codec_read(codec, 0x20, 0,
2030 AC_VERB_GET_PROC_COEF, 0);
2031 return val;
2032}
2033
Kailang Yang977ddd62010-09-15 10:02:29 +02002034static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
2035 unsigned int coef_val)
2036{
2037 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2038 coef_idx);
2039 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
2040 coef_val);
2041}
2042
Takashi Iwai757899a2010-07-30 10:48:14 +02002043/* set right pin controls for digital I/O */
2044static void alc_auto_init_digital(struct hda_codec *codec)
2045{
2046 struct alc_spec *spec = codec->spec;
2047 int i;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002048 hda_nid_t pin, dac;
Takashi Iwai757899a2010-07-30 10:48:14 +02002049
2050 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2051 pin = spec->autocfg.dig_out_pins[i];
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002052 if (!pin)
2053 continue;
2054 snd_hda_codec_write(codec, pin, 0,
2055 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
2056 if (!i)
2057 dac = spec->multiout.dig_out_nid;
2058 else
2059 dac = spec->slave_dig_outs[i - 1];
2060 if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
2061 continue;
2062 snd_hda_codec_write(codec, dac, 0,
2063 AC_VERB_SET_AMP_GAIN_MUTE,
2064 AMP_OUT_UNMUTE);
Takashi Iwai757899a2010-07-30 10:48:14 +02002065 }
2066 pin = spec->autocfg.dig_in_pin;
2067 if (pin)
2068 snd_hda_codec_write(codec, pin, 0,
2069 AC_VERB_SET_PIN_WIDGET_CONTROL,
2070 PIN_IN);
2071}
2072
2073/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
2074static void alc_auto_parse_digital(struct hda_codec *codec)
2075{
2076 struct alc_spec *spec = codec->spec;
2077 int i, err;
2078 hda_nid_t dig_nid;
2079
2080 /* support multiple SPDIFs; the secondary is set up as a slave */
2081 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2082 err = snd_hda_get_connections(codec,
2083 spec->autocfg.dig_out_pins[i],
2084 &dig_nid, 1);
2085 if (err < 0)
2086 continue;
2087 if (!i) {
2088 spec->multiout.dig_out_nid = dig_nid;
2089 spec->dig_out_type = spec->autocfg.dig_out_type[0];
2090 } else {
2091 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
2092 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
2093 break;
2094 spec->slave_dig_outs[i - 1] = dig_nid;
2095 }
2096 }
2097
2098 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02002099 dig_nid = codec->start_nid;
2100 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
2101 unsigned int wcaps = get_wcaps(codec, dig_nid);
2102 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
2103 continue;
2104 if (!(wcaps & AC_WCAP_DIGITAL))
2105 continue;
2106 if (!(wcaps & AC_WCAP_CONN_LIST))
2107 continue;
2108 err = get_connection_index(codec, dig_nid,
2109 spec->autocfg.dig_in_pin);
2110 if (err >= 0) {
2111 spec->dig_in_nid = dig_nid;
2112 break;
2113 }
2114 }
Takashi Iwai757899a2010-07-30 10:48:14 +02002115 }
2116}
2117
Takashi Iwaif95474e2007-07-10 00:47:43 +02002118/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002119 * ALC888
2120 */
2121
2122/*
2123 * 2ch mode
2124 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002125static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002126/* Mic-in jack as mic in */
2127 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2128 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2129/* Line-in jack as Line in */
2130 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2131 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2132/* Line-Out as Front */
2133 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2134 { } /* end */
2135};
2136
2137/*
2138 * 4ch mode
2139 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002140static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002141/* Mic-in jack as mic in */
2142 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2143 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2144/* Line-in jack as Surround */
2145 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2146 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2147/* Line-Out as Front */
2148 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2149 { } /* end */
2150};
2151
2152/*
2153 * 6ch mode
2154 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002155static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002156/* Mic-in jack as CLFE */
2157 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2158 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2159/* Line-in jack as Surround */
2160 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2161 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2162/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
2163 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2164 { } /* end */
2165};
2166
2167/*
2168 * 8ch mode
2169 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002170static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002171/* Mic-in jack as CLFE */
2172 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2173 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2174/* Line-in jack as Surround */
2175 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2176 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2177/* Line-Out as Side */
2178 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2179 { } /* end */
2180};
2181
Takashi Iwaia9111322011-05-02 11:30:18 +02002182static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002183 { 2, alc888_4ST_ch2_intel_init },
2184 { 4, alc888_4ST_ch4_intel_init },
2185 { 6, alc888_4ST_ch6_intel_init },
2186 { 8, alc888_4ST_ch8_intel_init },
2187};
2188
2189/*
2190 * ALC888 Fujitsu Siemens Amillo xa3530
2191 */
2192
Takashi Iwaia9111322011-05-02 11:30:18 +02002193static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002194/* Front Mic: set to PIN_IN (empty by default) */
2195 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2196/* Connect Internal HP to Front */
2197 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2198 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2199 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2200/* Connect Bass HP to Front */
2201 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2202 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2203 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2204/* Connect Line-Out side jack (SPDIF) to Side */
2205 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2206 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2207 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2208/* Connect Mic jack to CLFE */
2209 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2210 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2211 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
2212/* Connect Line-in jack to Surround */
2213 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2214 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2215 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
2216/* Connect HP out jack to Front */
2217 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2218 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2219 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2220/* Enable unsolicited event for HP jack and Line-out jack */
2221 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2222 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2223 {}
2224};
2225
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002226static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02002227{
2228 struct alc_spec *spec = codec->spec;
2229
2230 spec->autocfg.hp_pins[0] = 0x15;
2231 spec->autocfg.speaker_pins[0] = 0x14;
2232 spec->autocfg.speaker_pins[1] = 0x16;
2233 spec->autocfg.speaker_pins[2] = 0x17;
2234 spec->autocfg.speaker_pins[3] = 0x19;
2235 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02002236 spec->automute = 1;
2237 spec->automute_mode = ALC_AUTOMUTE_AMP;
Wu Fengguang6732bd02009-07-30 09:19:14 +02002238}
2239
2240static void alc889_intel_init_hook(struct hda_codec *codec)
2241{
2242 alc889_coef_init(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02002243 alc_hp_automute(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02002244}
2245
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002246static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002247{
2248 struct alc_spec *spec = codec->spec;
2249
2250 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
2251 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
2252 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
2253 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaid922b512011-04-28 12:18:53 +02002254 spec->automute = 1;
2255 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002256}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002257
2258/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002259 * ALC888 Acer Aspire 4930G model
2260 */
2261
Takashi Iwaia9111322011-05-02 11:30:18 +02002262static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002263/* Front Mic: set to PIN_IN (empty by default) */
2264 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2265/* Unselect Front Mic by default in input mixer 3 */
2266 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002267/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002268 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2269/* Connect Internal HP to front */
2270 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2271 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2272 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2273/* Connect HP out to front */
2274 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2275 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2276 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie2e93292011-01-12 08:03:39 +01002277 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002278 { }
2279};
2280
Hector Martin3b315d72009-06-02 10:54:19 +02002281/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01002282 * ALC888 Acer Aspire 6530G model
2283 */
2284
Takashi Iwaia9111322011-05-02 11:30:18 +02002285static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01002286/* Route to built-in subwoofer as well as speakers */
2287 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2288 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2289 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2290 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002291/* Bias voltage on for external mic port */
2292 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02002293/* Front Mic: set to PIN_IN (empty by default) */
2294 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2295/* Unselect Front Mic by default in input mixer 3 */
2296 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002297/* Enable unsolicited event for HP jack */
2298 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2299/* Enable speaker output */
2300 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2301 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01002302 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002303/* Enable headphone output */
2304 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2305 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2306 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01002307 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002308 { }
2309};
2310
2311/*
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002312 *ALC888 Acer Aspire 7730G model
2313 */
2314
Takashi Iwaia9111322011-05-02 11:30:18 +02002315static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002316/* Bias voltage on for external mic port */
2317 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
2318/* Front Mic: set to PIN_IN (empty by default) */
2319 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2320/* Unselect Front Mic by default in input mixer 3 */
2321 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2322/* Enable unsolicited event for HP jack */
2323 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2324/* Enable speaker output */
2325 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2326 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2327 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
2328/* Enable headphone output */
2329 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2330 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2331 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2332 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
2333/*Enable internal subwoofer */
2334 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2335 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2336 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
2337 {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
2338 { }
2339};
2340
2341/*
Hector Martin018df412009-06-04 00:13:40 +02002342 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02002343 */
2344
Takashi Iwaia9111322011-05-02 11:30:18 +02002345static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02002346/* Front Mic: set to PIN_IN (empty by default) */
2347 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2348/* Unselect Front Mic by default in input mixer 3 */
2349 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2350/* Enable unsolicited event for HP jack */
2351 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2352/* Connect Internal Front to Front */
2353 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2354 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2355 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2356/* Connect Internal Rear to Rear */
2357 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2358 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2359 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2360/* Connect Internal CLFE to CLFE */
2361 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2362 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2363 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2364/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002365 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002366 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2367 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2368/* Enable all DACs */
2369/* DAC DISABLE/MUTE 1? */
2370/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2371 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2372 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2373/* DAC DISABLE/MUTE 2? */
2374/* some bit here disables the other DACs. Init=0x4900 */
2375 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2376 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002377/* DMIC fix
2378 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2379 * which makes the stereo useless. However, either the mic or the ALC889
2380 * makes the signal become a difference/sum signal instead of standard
2381 * stereo, which is annoying. So instead we flip this bit which makes the
2382 * codec replicate the sum signal to both channels, turning it into a
2383 * normal mono mic.
2384 */
2385/* DMIC_CONTROL? Init value = 0x0001 */
2386 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2387 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002388 { }
2389};
2390
Takashi Iwaia9111322011-05-02 11:30:18 +02002391static const struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002392 /* Front mic only available on one ADC */
2393 {
2394 .num_items = 4,
2395 .items = {
2396 { "Mic", 0x0 },
2397 { "Line", 0x2 },
2398 { "CD", 0x4 },
2399 { "Front Mic", 0xb },
2400 },
2401 },
2402 {
2403 .num_items = 3,
2404 .items = {
2405 { "Mic", 0x0 },
2406 { "Line", 0x2 },
2407 { "CD", 0x4 },
2408 },
2409 }
2410};
2411
Takashi Iwaia9111322011-05-02 11:30:18 +02002412static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01002413 /* Interal mic only available on one ADC */
2414 {
Tony Vroon684a8842009-06-26 09:27:50 +01002415 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002416 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002417 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002418 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002419 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002420 { "Input Mix", 0xa },
David Henningsson28c4edb2010-12-20 14:24:29 +01002421 { "Internal Mic", 0xb },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002422 },
2423 },
2424 {
Tony Vroon684a8842009-06-26 09:27:50 +01002425 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002426 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002427 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002428 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002429 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002430 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002431 },
2432 }
2433};
2434
Takashi Iwaia9111322011-05-02 11:30:18 +02002435static const struct hda_input_mux alc889_capture_sources[3] = {
Hector Martin018df412009-06-04 00:13:40 +02002436 /* Digital mic only available on first "ADC" */
2437 {
2438 .num_items = 5,
2439 .items = {
2440 { "Mic", 0x0 },
2441 { "Line", 0x2 },
2442 { "CD", 0x4 },
2443 { "Front Mic", 0xb },
2444 { "Input Mix", 0xa },
2445 },
2446 },
2447 {
2448 .num_items = 4,
2449 .items = {
2450 { "Mic", 0x0 },
2451 { "Line", 0x2 },
2452 { "CD", 0x4 },
2453 { "Input Mix", 0xa },
2454 },
2455 },
2456 {
2457 .num_items = 4,
2458 .items = {
2459 { "Mic", 0x0 },
2460 { "Line", 0x2 },
2461 { "CD", 0x4 },
2462 { "Input Mix", 0xa },
2463 },
2464 }
2465};
2466
Takashi Iwaia9111322011-05-02 11:30:18 +02002467static const struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002468 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2469 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2470 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2471 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2472 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2473 HDA_OUTPUT),
2474 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2475 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2476 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2477 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2478 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2479 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2480 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2481 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2482 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2483 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002484 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002485 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002486 { } /* end */
2487};
2488
Takashi Iwaia9111322011-05-02 11:30:18 +02002489static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002490 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2491 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2492 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2493 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002494 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002495 HDA_OUTPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002496 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2497 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2498 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2499 HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
2500 HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002501 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2502 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2503 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2504 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2505 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2506 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
2507 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2508 { } /* end */
2509};
2510
Takashi Iwaia9111322011-05-02 11:30:18 +02002511static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
Hector Martin556eea92009-12-20 22:51:23 +01002512 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2513 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2514 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2515 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2516 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2517 HDA_OUTPUT),
2518 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2519 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2520 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2521 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2522 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2523 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002524 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002525 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2526 { } /* end */
2527};
2528
2529
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002530static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002531{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002532 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002533
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002534 spec->autocfg.hp_pins[0] = 0x15;
2535 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002536 spec->autocfg.speaker_pins[1] = 0x16;
2537 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002538 spec->automute = 1;
2539 spec->automute_mode = ALC_AUTOMUTE_AMP;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002540}
2541
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002542static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002543{
2544 struct alc_spec *spec = codec->spec;
2545
2546 spec->autocfg.hp_pins[0] = 0x15;
2547 spec->autocfg.speaker_pins[0] = 0x14;
2548 spec->autocfg.speaker_pins[1] = 0x16;
2549 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002550 spec->automute = 1;
2551 spec->automute_mode = ALC_AUTOMUTE_AMP;
Emilio López320d5922009-06-25 08:18:44 +02002552}
2553
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002554static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2555{
2556 struct alc_spec *spec = codec->spec;
2557
2558 spec->autocfg.hp_pins[0] = 0x15;
2559 spec->autocfg.speaker_pins[0] = 0x14;
2560 spec->autocfg.speaker_pins[1] = 0x16;
2561 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002562 spec->automute = 1;
2563 spec->automute_mode = ALC_AUTOMUTE_AMP;
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002564}
2565
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002566static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002567{
2568 struct alc_spec *spec = codec->spec;
2569
2570 spec->autocfg.hp_pins[0] = 0x15;
2571 spec->autocfg.speaker_pins[0] = 0x14;
2572 spec->autocfg.speaker_pins[1] = 0x16;
2573 spec->autocfg.speaker_pins[2] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02002574 spec->automute = 1;
2575 spec->automute_mode = ALC_AUTOMUTE_AMP;
Hector Martin3b315d72009-06-02 10:54:19 +02002576}
2577
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002578/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002579 * ALC880 3-stack model
2580 *
2581 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002582 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2583 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 */
2585
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002586static const hda_nid_t alc880_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002587 /* front, rear, clfe, rear_surr */
2588 0x02, 0x05, 0x04, 0x03
2589};
2590
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002591static const hda_nid_t alc880_adc_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002592 /* ADC0-2 */
2593 0x07, 0x08, 0x09,
2594};
2595
2596/* The datasheet says the node 0x07 is connected from inputs,
2597 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002598 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002600static const hda_nid_t alc880_adc_nids_alt[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002601 /* ADC1-2 */
2602 0x08, 0x09,
2603};
2604
2605#define ALC880_DIGOUT_NID 0x06
2606#define ALC880_DIGIN_NID 0x0a
2607
Takashi Iwaia9111322011-05-02 11:30:18 +02002608static const struct hda_input_mux alc880_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002609 .num_items = 4,
2610 .items = {
2611 { "Mic", 0x0 },
2612 { "Front Mic", 0x3 },
2613 { "Line", 0x2 },
2614 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002616};
2617
2618/* channel source setting (2/6 channel selection for 3-stack) */
2619/* 2ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002620static const struct hda_verb alc880_threestack_ch2_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002621 /* set line-in to input, mute it */
2622 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2623 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2624 /* set mic-in to input vref 80%, mute it */
2625 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2626 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 { } /* end */
2628};
2629
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002630/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002631static const struct hda_verb alc880_threestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002632 /* set line-in to output, unmute it */
2633 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2634 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2635 /* set mic-in to output, unmute it */
2636 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2637 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2638 { } /* end */
2639};
2640
Takashi Iwaia9111322011-05-02 11:30:18 +02002641static const struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002642 { 2, alc880_threestack_ch2_init },
2643 { 6, alc880_threestack_ch6_init },
2644};
2645
Takashi Iwaia9111322011-05-02 11:30:18 +02002646static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002647 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002648 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002649 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002650 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002651 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2652 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002653 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2654 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2656 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2657 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2658 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2659 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2660 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2661 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2662 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002664 {
2665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2666 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002667 .info = alc_ch_mode_info,
2668 .get = alc_ch_mode_get,
2669 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002670 },
2671 { } /* end */
2672};
2673
2674/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002675static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2676 struct snd_ctl_elem_info *uinfo)
2677{
2678 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2679 struct alc_spec *spec = codec->spec;
2680 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002681
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002682 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002683 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2684 HDA_INPUT);
2685 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002686 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002687 return err;
2688}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002690static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2691 unsigned int size, unsigned int __user *tlv)
2692{
2693 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2694 struct alc_spec *spec = codec->spec;
2695 int err;
2696
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002697 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002698 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2699 HDA_INPUT);
2700 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002701 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002702 return err;
2703}
2704
2705typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2706 struct snd_ctl_elem_value *ucontrol);
2707
2708static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2709 struct snd_ctl_elem_value *ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002710 getput_call_t func, bool check_adc_switch)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002711{
2712 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2713 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002714 int i, err;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002715
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002716 mutex_lock(&codec->control_mutex);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002717 if (check_adc_switch && spec->dual_adc_switch) {
2718 for (i = 0; i < spec->num_adc_nids; i++) {
2719 kcontrol->private_value =
2720 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2721 3, 0, HDA_INPUT);
2722 err = func(kcontrol, ucontrol);
2723 if (err < 0)
2724 goto error;
2725 }
2726 } else {
2727 i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2728 kcontrol->private_value =
2729 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2730 3, 0, HDA_INPUT);
2731 err = func(kcontrol, ucontrol);
2732 }
2733 error:
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002734 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002735 return err;
2736}
2737
2738static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2739 struct snd_ctl_elem_value *ucontrol)
2740{
2741 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002742 snd_hda_mixer_amp_volume_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002743}
2744
2745static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2746 struct snd_ctl_elem_value *ucontrol)
2747{
2748 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002749 snd_hda_mixer_amp_volume_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002750}
2751
2752/* capture mixer elements */
2753#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2754
2755static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2756 struct snd_ctl_elem_value *ucontrol)
2757{
2758 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002759 snd_hda_mixer_amp_switch_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002760}
2761
2762static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2763 struct snd_ctl_elem_value *ucontrol)
2764{
2765 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002766 snd_hda_mixer_amp_switch_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002767}
2768
Takashi Iwaia23b6882009-03-23 15:21:36 +01002769#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002770 { \
2771 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2772 .name = "Capture Switch", \
2773 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2774 .count = num, \
2775 .info = alc_cap_sw_info, \
2776 .get = alc_cap_sw_get, \
2777 .put = alc_cap_sw_put, \
2778 }, \
2779 { \
2780 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2781 .name = "Capture Volume", \
2782 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2783 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2784 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2785 .count = num, \
2786 .info = alc_cap_vol_info, \
2787 .get = alc_cap_vol_get, \
2788 .put = alc_cap_vol_put, \
2789 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002790 }
2791
2792#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002793 { \
2794 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2795 /* .name = "Capture Source", */ \
2796 .name = "Input Source", \
2797 .count = num, \
2798 .info = alc_mux_enum_info, \
2799 .get = alc_mux_enum_get, \
2800 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002801 }
2802
2803#define DEFINE_CAPMIX(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002804static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002805 _DEFINE_CAPMIX(num), \
2806 _DEFINE_CAPSRC(num), \
2807 { } /* end */ \
2808}
2809
2810#define DEFINE_CAPMIX_NOSRC(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002811static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002812 _DEFINE_CAPMIX(num), \
2813 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002814}
2815
2816/* up to three ADCs */
2817DEFINE_CAPMIX(1);
2818DEFINE_CAPMIX(2);
2819DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002820DEFINE_CAPMIX_NOSRC(1);
2821DEFINE_CAPMIX_NOSRC(2);
2822DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002823
2824/*
2825 * ALC880 5-stack model
2826 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002827 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2828 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002829 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2830 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2831 */
2832
2833/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02002834static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002835 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002836 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 { } /* end */
2838};
2839
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002840/* channel source setting (6/8 channel selection for 5-stack) */
2841/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002842static const struct hda_verb alc880_fivestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002843 /* set line-in to input, mute it */
2844 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2845 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002846 { } /* end */
2847};
2848
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002849/* 8ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002850static const struct hda_verb alc880_fivestack_ch8_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002851 /* set line-in to output, unmute it */
2852 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2853 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2854 { } /* end */
2855};
2856
Takashi Iwaia9111322011-05-02 11:30:18 +02002857static const struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002858 { 6, alc880_fivestack_ch6_init },
2859 { 8, alc880_fivestack_ch8_init },
2860};
2861
2862
2863/*
2864 * ALC880 6-stack model
2865 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002866 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2867 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002868 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2869 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2870 */
2871
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002872static const hda_nid_t alc880_6st_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002873 /* front, rear, clfe, rear_surr */
2874 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002875};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002876
Takashi Iwaia9111322011-05-02 11:30:18 +02002877static const struct hda_input_mux alc880_6stack_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002878 .num_items = 4,
2879 .items = {
2880 { "Mic", 0x0 },
2881 { "Front Mic", 0x1 },
2882 { "Line", 0x2 },
2883 { "CD", 0x4 },
2884 },
2885};
2886
2887/* fixed 8-channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002888static const struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002889 { 8, NULL },
2890};
2891
Takashi Iwaia9111322011-05-02 11:30:18 +02002892static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002893 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002894 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002895 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002896 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002897 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2898 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002899 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2900 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002901 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002902 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002903 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2904 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2905 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2906 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2907 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2908 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2909 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2910 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002911 {
2912 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2913 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002914 .info = alc_ch_mode_info,
2915 .get = alc_ch_mode_get,
2916 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002917 },
2918 { } /* end */
2919};
2920
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002921
2922/*
2923 * ALC880 W810 model
2924 *
2925 * W810 has rear IO for:
2926 * Front (DAC 02)
2927 * Surround (DAC 03)
2928 * Center/LFE (DAC 04)
2929 * Digital out (06)
2930 *
2931 * The system also has a pair of internal speakers, and a headphone jack.
2932 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002933 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002934 * There is a variable resistor to control the speaker or headphone
2935 * volume. This is a hardware-only device without a software API.
2936 *
2937 * Plugging headphones in will disable the internal speakers. This is
2938 * implemented in hardware, not via the driver using jack sense. In
2939 * a similar fashion, plugging into the rear socket marked "front" will
2940 * disable both the speakers and headphones.
2941 *
2942 * For input, there's a microphone jack, and an "audio in" jack.
2943 * These may not do anything useful with this driver yet, because I
2944 * haven't setup any initialization verbs for these yet...
2945 */
2946
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002947static const hda_nid_t alc880_w810_dac_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002948 /* front, rear/surround, clfe */
2949 0x02, 0x03, 0x04
2950};
2951
2952/* fixed 6 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002953static const struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002954 { 6, NULL }
2955};
2956
2957/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaia9111322011-05-02 11:30:18 +02002958static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002959 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002960 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002961 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002962 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002963 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2964 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002965 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2966 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002967 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2968 { } /* end */
2969};
2970
2971
2972/*
2973 * Z710V model
2974 *
2975 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002976 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2977 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002978 */
2979
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002980static const hda_nid_t alc880_z71v_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002981 0x02
2982};
2983#define ALC880_Z71V_HP_DAC 0x03
2984
2985/* fixed 2 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002986static const struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002987 { 2, NULL }
2988};
2989
Takashi Iwaia9111322011-05-02 11:30:18 +02002990static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002991 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002992 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002993 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002994 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002995 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2996 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2997 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2998 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2999 { } /* end */
3000};
3001
3002
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003003/*
3004 * ALC880 F1734 model
3005 *
3006 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
3007 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
3008 */
3009
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003010static const hda_nid_t alc880_f1734_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003011 0x03
3012};
3013#define ALC880_F1734_HP_DAC 0x02
3014
Takashi Iwaia9111322011-05-02 11:30:18 +02003015static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003016 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003017 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01003018 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3019 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003020 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3021 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01003022 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3023 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003024 { } /* end */
3025};
3026
Takashi Iwaia9111322011-05-02 11:30:18 +02003027static const struct hda_input_mux alc880_f1734_capture_source = {
Takashi Iwai937b4162008-02-11 14:52:36 +01003028 .num_items = 2,
3029 .items = {
3030 { "Mic", 0x1 },
3031 { "CD", 0x4 },
3032 },
3033};
3034
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003035
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003036/*
3037 * ALC880 ASUS model
3038 *
3039 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3040 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3041 * Mic = 0x18, Line = 0x1a
3042 */
3043
3044#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
3045#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
3046
Takashi Iwaia9111322011-05-02 11:30:18 +02003047static const struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003048 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003049 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003050 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003051 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003052 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3053 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003054 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3055 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003056 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3057 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3058 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3059 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3060 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3061 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003062 {
3063 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3064 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003065 .info = alc_ch_mode_info,
3066 .get = alc_ch_mode_get,
3067 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02003068 },
3069 { } /* end */
3070};
3071
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003072/*
3073 * ALC880 ASUS W1V model
3074 *
3075 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3076 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3077 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
3078 */
3079
3080/* additional mixers to alc880_asus_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02003081static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003082 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
3083 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003084 { } /* end */
3085};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003086
Kailang Yangdf694da2005-12-05 19:42:22 +01003087/* TCL S700 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003088static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003089 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3090 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3091 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
3092 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
3093 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
3094 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
3095 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
3096 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3097 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003098 { } /* end */
3099};
3100
Kailang Yangccc656c2006-10-17 12:32:26 +02003101/* Uniwill */
Takashi Iwaia9111322011-05-02 11:30:18 +02003102static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003103 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3104 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3105 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3106 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003107 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3108 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3109 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3110 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3111 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3112 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3113 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3114 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3115 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3116 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3117 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3118 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003119 {
3120 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3121 .name = "Channel Mode",
3122 .info = alc_ch_mode_info,
3123 .get = alc_ch_mode_get,
3124 .put = alc_ch_mode_put,
3125 },
3126 { } /* end */
3127};
3128
Takashi Iwaia9111322011-05-02 11:30:18 +02003129static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003130 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3131 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3132 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3133 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
3134 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3135 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01003136 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3137 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01003138 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3139 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003140 { } /* end */
3141};
3142
Takashi Iwaia9111322011-05-02 11:30:18 +02003143static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003144 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3145 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3146 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3147 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003148 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3149 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3150 { } /* end */
3151};
3152
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01003154 * virtual master controls
3155 */
3156
3157/*
3158 * slave controls for virtual master
3159 */
Takashi Iwaiea734962011-01-17 11:29:34 +01003160static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003161 "Front Playback Volume",
3162 "Surround Playback Volume",
3163 "Center Playback Volume",
3164 "LFE Playback Volume",
3165 "Side Playback Volume",
3166 "Headphone Playback Volume",
3167 "Speaker Playback Volume",
3168 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003169 "Line-Out Playback Volume",
3170 NULL,
3171};
3172
Takashi Iwaiea734962011-01-17 11:29:34 +01003173static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003174 "Front Playback Switch",
3175 "Surround Playback Switch",
3176 "Center Playback Switch",
3177 "LFE Playback Switch",
3178 "Side Playback Switch",
3179 "Headphone Playback Switch",
3180 "Speaker Playback Switch",
3181 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01003182 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01003183 "Line-Out Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003184 NULL,
3185};
3186
3187/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003188 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 */
Takashi Iwai603c4012008-07-30 15:01:44 +02003190
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003191#define NID_MAPPING (-1)
3192
3193#define SUBDEV_SPEAKER_ (0 << 6)
3194#define SUBDEV_HP_ (1 << 6)
3195#define SUBDEV_LINE_ (2 << 6)
3196#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
3197#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
3198#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
3199
Takashi Iwai603c4012008-07-30 15:01:44 +02003200static void alc_free_kctls(struct hda_codec *codec);
3201
Takashi Iwai67d634c2009-11-16 15:35:59 +01003202#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003203/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02003204static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003205 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003206 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003207 { } /* end */
3208};
Takashi Iwai67d634c2009-11-16 15:35:59 +01003209#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003210
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211static int alc_build_controls(struct hda_codec *codec)
3212{
3213 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02003214 struct snd_kcontrol *kctl = NULL;
Takashi Iwaia9111322011-05-02 11:30:18 +02003215 const struct snd_kcontrol_new *knew;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003216 int i, j, err;
3217 unsigned int u;
3218 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220 for (i = 0; i < spec->num_mixers; i++) {
3221 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
3222 if (err < 0)
3223 return err;
3224 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003225 if (spec->cap_mixer) {
3226 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
3227 if (err < 0)
3228 return err;
3229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003231 err = snd_hda_create_spdif_out_ctls(codec,
Stephen Warren74b654c2011-06-01 11:14:18 -06003232 spec->multiout.dig_out_nid,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003233 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 if (err < 0)
3235 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003236 if (!spec->no_analog) {
3237 err = snd_hda_create_spdif_share_sw(codec,
3238 &spec->multiout);
3239 if (err < 0)
3240 return err;
3241 spec->multiout.share_spdif = 1;
3242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 }
3244 if (spec->dig_in_nid) {
3245 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3246 if (err < 0)
3247 return err;
3248 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01003249
Takashi Iwai67d634c2009-11-16 15:35:59 +01003250#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003251 /* create beep controls if needed */
3252 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02003253 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003254 for (knew = alc_beep_mixer; knew->name; knew++) {
3255 struct snd_kcontrol *kctl;
3256 kctl = snd_ctl_new1(knew, codec);
3257 if (!kctl)
3258 return -ENOMEM;
3259 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003260 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003261 if (err < 0)
3262 return err;
3263 }
3264 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01003265#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003266
Takashi Iwai2134ea42008-01-10 16:53:55 +01003267 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003268 if (!spec->no_analog &&
3269 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003270 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01003271 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003272 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003273 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003274 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003275 if (err < 0)
3276 return err;
3277 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003278 if (!spec->no_analog &&
3279 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003280 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
3281 NULL, alc_slave_sws);
3282 if (err < 0)
3283 return err;
3284 }
3285
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003286 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003287 if (spec->capsrc_nids || spec->adc_nids) {
3288 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
3289 if (!kctl)
3290 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3291 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003292 const hda_nid_t *nids = spec->capsrc_nids;
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003293 if (!nids)
3294 nids = spec->adc_nids;
3295 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3296 if (err < 0)
3297 return err;
3298 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003299 }
3300 if (spec->cap_mixer) {
3301 const char *kname = kctl ? kctl->id.name : NULL;
3302 for (knew = spec->cap_mixer; knew->name; knew++) {
3303 if (kname && strcmp(knew->name, kname) == 0)
3304 continue;
3305 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3306 for (i = 0; kctl && i < kctl->count; i++) {
3307 err = snd_hda_add_nid(codec, kctl, i,
3308 spec->adc_nids[i]);
3309 if (err < 0)
3310 return err;
3311 }
3312 }
3313 }
3314
3315 /* other nid->control mapping */
3316 for (i = 0; i < spec->num_mixers; i++) {
3317 for (knew = spec->mixers[i]; knew->name; knew++) {
3318 if (knew->iface != NID_MAPPING)
3319 continue;
3320 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3321 if (kctl == NULL)
3322 continue;
3323 u = knew->subdevice;
3324 for (j = 0; j < 4; j++, u >>= 8) {
3325 nid = u & 0x3f;
3326 if (nid == 0)
3327 continue;
3328 switch (u & 0xc0) {
3329 case SUBDEV_SPEAKER_:
3330 nid = spec->autocfg.speaker_pins[nid];
3331 break;
3332 case SUBDEV_LINE_:
3333 nid = spec->autocfg.line_out_pins[nid];
3334 break;
3335 case SUBDEV_HP_:
3336 nid = spec->autocfg.hp_pins[nid];
3337 break;
3338 default:
3339 continue;
3340 }
3341 err = snd_hda_add_nid(codec, kctl, 0, nid);
3342 if (err < 0)
3343 return err;
3344 }
3345 u = knew->private_value;
3346 for (j = 0; j < 4; j++, u >>= 8) {
3347 nid = u & 0xff;
3348 if (nid == 0)
3349 continue;
3350 err = snd_hda_add_nid(codec, kctl, 0, nid);
3351 if (err < 0)
3352 return err;
3353 }
3354 }
3355 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003356
3357 alc_free_kctls(codec); /* no longer needed */
3358
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 return 0;
3360}
3361
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003362
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363/*
3364 * initialize the codec volumes, etc
3365 */
3366
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003367/*
3368 * generic initialization of ADC, input mixers and output mixers
3369 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003370static const struct hda_verb alc880_volume_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003371 /*
3372 * Unmute ADC0-2 and set the default input to mic-in
3373 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003374 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003375 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003376 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003377 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003378 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003379 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003381 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3382 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003383 * Note: PASD motherboards uses the Line In 2 as the input for front
3384 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003386 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003387 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3388 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3389 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3390 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3391 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3392 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3393 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003395 /*
3396 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003398 /* set vol=0 to output mixers */
3399 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3400 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3401 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3402 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3403 /* set up input amps for analog loopback */
3404 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003405 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3406 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003407 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3408 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003409 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3410 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003411 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3412 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413
3414 { }
3415};
3416
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003417/*
3418 * 3-stack pin configuration:
3419 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3420 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003421static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003422 /*
3423 * preset connection lists of input pins
3424 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3425 */
3426 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3427 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3428 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3429
3430 /*
3431 * Set pin mode and muting
3432 */
3433 /* set front pin widgets 0x14 for output */
3434 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3435 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3436 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3437 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3438 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3439 /* Mic2 (as headphone out) for HP output */
3440 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3441 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3442 /* Line In pin widget for input */
3443 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3444 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3445 /* Line2 (as front mic) pin widget for input and vref at 80% */
3446 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3447 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3448 /* CD pin widget for input */
3449 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3450
3451 { }
3452};
3453
3454/*
3455 * 5-stack pin configuration:
3456 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3457 * line-in/side = 0x1a, f-mic = 0x1b
3458 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003459static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003460 /*
3461 * preset connection lists of input pins
3462 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3463 */
3464 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3465 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3466
3467 /*
3468 * Set pin mode and muting
3469 */
3470 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003471 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3472 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3473 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3474 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003475 /* unmute pins for output (no gain on this amp) */
3476 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3477 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3478 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3479 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3480
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003482 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003483 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3484 /* Mic2 (as headphone out) for HP output */
3485 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003486 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003487 /* Line In pin widget for input */
3488 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3489 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3490 /* Line2 (as front mic) pin widget for input and vref at 80% */
3491 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3492 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3493 /* CD pin widget for input */
3494 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495
3496 { }
3497};
3498
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003499/*
3500 * W810 pin configuration:
3501 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3502 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003503static const struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 /* hphone/speaker input selector: front DAC */
3505 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3506
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003507 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3508 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3509 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3511 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3512 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3513
3514 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003515 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 { }
3518};
3519
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003520/*
3521 * Z71V pin configuration:
3522 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3523 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003524static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003525 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003526 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003527 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003528 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003529
Takashi Iwai16ded522005-06-10 19:58:24 +02003530 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003531 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003532 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003533 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003534
3535 { }
3536};
3537
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003538/*
3539 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003540 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3541 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003542 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003543static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003544 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3545
Takashi Iwai16ded522005-06-10 19:58:24 +02003546 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003547 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003548 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003549 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003550 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003551 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003552 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003553 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3554
Takashi Iwai16ded522005-06-10 19:58:24 +02003555 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003556 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003557 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003558 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003559 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003560 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003561 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003562 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003563 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003564
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003565 { }
3566};
Takashi Iwai16ded522005-06-10 19:58:24 +02003567
Kailang Yangccc656c2006-10-17 12:32:26 +02003568/*
3569 * Uniwill pin configuration:
3570 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3571 * line = 0x1a
3572 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003573static const struct hda_verb alc880_uniwill_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003574 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3575
3576 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3577 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3578 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3579 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3580 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3581 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3582 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3583 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3584 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3585 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3586 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3587 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3588 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3589 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3590
3591 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3592 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3593 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3594 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3595 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3596 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3597 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3598 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3599 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3600
3601 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3602 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3603
3604 { }
3605};
3606
3607/*
3608* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003609* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003610 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003611static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003612 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3613
3614 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3615 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3616 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3617 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3618 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3619 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3620 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3621 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3622 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3623 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3624 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3625 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3626
3627 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3628 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3629 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3630 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3631 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3632 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3633
3634 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3635 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3636
3637 { }
3638};
3639
Takashi Iwaia9111322011-05-02 11:30:18 +02003640static const struct hda_verb alc880_beep_init_verbs[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003641 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3642 { }
3643};
3644
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003645/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003646static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003647{
3648 unsigned int present;
3649 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003650
Wu Fengguang864f92b2009-11-18 12:38:02 +08003651 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003652 bits = present ? HDA_AMP_MUTE : 0;
3653 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003654}
3655
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003656static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003657{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003658 struct alc_spec *spec = codec->spec;
3659
3660 spec->autocfg.hp_pins[0] = 0x14;
3661 spec->autocfg.speaker_pins[0] = 0x15;
3662 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02003663 spec->automute = 1;
3664 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003665}
3666
3667static void alc880_uniwill_init_hook(struct hda_codec *codec)
3668{
Takashi Iwaid922b512011-04-28 12:18:53 +02003669 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003670 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003671}
3672
3673static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3674 unsigned int res)
3675{
3676 /* Looks like the unsol event is incompatible with the standard
3677 * definition. 4bit tag is placed at 28 bit!
3678 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003679 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003680 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003681 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003682 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003683 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02003684 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003685 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003686 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003687}
3688
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003689static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003690{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003691 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003692
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003693 spec->autocfg.hp_pins[0] = 0x14;
3694 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02003695 spec->automute = 1;
3696 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangccc656c2006-10-17 12:32:26 +02003697}
3698
3699static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3700{
3701 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003702
Kailang Yangccc656c2006-10-17 12:32:26 +02003703 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003704 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3705 present &= HDA_AMP_VOLMASK;
3706 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3707 HDA_AMP_VOLMASK, present);
3708 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3709 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003710}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003711
Kailang Yangccc656c2006-10-17 12:32:26 +02003712static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3713 unsigned int res)
3714{
3715 /* Looks like the unsol event is incompatible with the standard
3716 * definition. 4bit tag is placed at 28 bit!
3717 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003718 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003719 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003720 else
Takashi Iwaid922b512011-04-28 12:18:53 +02003721 alc_sku_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003722}
3723
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003724/*
3725 * F1734 pin configuration:
3726 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3727 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003728static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003729 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003730 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3731 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3732 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3733 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3734
3735 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3736 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3737 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3738 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3739
3740 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3741 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003742 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003743 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3744 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3745 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3746 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3747 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3748 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003749
Takashi Iwai937b4162008-02-11 14:52:36 +01003750 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3751 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3752
Takashi Iwai16ded522005-06-10 19:58:24 +02003753 { }
3754};
3755
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003756/*
3757 * ASUS pin configuration:
3758 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3759 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003760static const struct hda_verb alc880_pin_asus_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003761 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3762 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3763 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3764 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3765
3766 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3767 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3768 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3769 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3770 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3771 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3772 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3773 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3774
3775 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3776 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3777 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3778 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3779 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3780 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3781 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3782 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3783 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003784
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003785 { }
3786};
3787
3788/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003789#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3790#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003791#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003792
Kailang Yangdf694da2005-12-05 19:42:22 +01003793/* Clevo m520g init */
Takashi Iwaia9111322011-05-02 11:30:18 +02003794static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003795 /* headphone output */
3796 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3797 /* line-out */
3798 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3799 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3800 /* Line-in */
3801 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3802 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3803 /* CD */
3804 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3805 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3806 /* Mic1 (rear panel) */
3807 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3808 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3809 /* Mic2 (front panel) */
3810 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3811 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3812 /* headphone */
3813 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3814 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3815 /* change to EAPD mode */
3816 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3817 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3818
3819 { }
3820};
3821
Takashi Iwaia9111322011-05-02 11:30:18 +02003822static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003823 /* change to EAPD mode */
3824 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3825 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3826
Kailang Yangdf694da2005-12-05 19:42:22 +01003827 /* Headphone output */
3828 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3829 /* Front output*/
3830 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3831 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3832
3833 /* Line In pin widget for input */
3834 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3835 /* CD pin widget for input */
3836 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3837 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3838 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3839
3840 /* change to EAPD mode */
3841 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3842 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3843
3844 { }
3845};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003846
3847/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003848 * LG m1 express dual
3849 *
3850 * Pin assignment:
3851 * Rear Line-In/Out (blue): 0x14
3852 * Build-in Mic-In: 0x15
3853 * Speaker-out: 0x17
3854 * HP-Out (green): 0x1b
3855 * Mic-In/Out (red): 0x19
3856 * SPDIF-Out: 0x1e
3857 */
3858
3859/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003860static const hda_nid_t alc880_lg_dac_nids[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003861 0x05, 0x02, 0x03
3862};
3863
3864/* seems analog CD is not working */
Takashi Iwaia9111322011-05-02 11:30:18 +02003865static const struct hda_input_mux alc880_lg_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003866 .num_items = 3,
3867 .items = {
3868 { "Mic", 0x1 },
3869 { "Line", 0x5 },
3870 { "Internal Mic", 0x6 },
3871 },
3872};
3873
3874/* 2,4,6 channel modes */
Takashi Iwaia9111322011-05-02 11:30:18 +02003875static const struct hda_verb alc880_lg_ch2_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003876 /* set line-in and mic-in to input */
3877 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3878 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3879 { }
3880};
3881
Takashi Iwaia9111322011-05-02 11:30:18 +02003882static const struct hda_verb alc880_lg_ch4_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003883 /* set line-in to out and mic-in to input */
3884 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3885 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3886 { }
3887};
3888
Takashi Iwaia9111322011-05-02 11:30:18 +02003889static const struct hda_verb alc880_lg_ch6_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003890 /* set line-in and mic-in to output */
3891 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3892 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3893 { }
3894};
3895
Takashi Iwaia9111322011-05-02 11:30:18 +02003896static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003897 { 2, alc880_lg_ch2_init },
3898 { 4, alc880_lg_ch4_init },
3899 { 6, alc880_lg_ch6_init },
3900};
3901
Takashi Iwaia9111322011-05-02 11:30:18 +02003902static const struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003903 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3904 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003905 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3906 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3907 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3908 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3909 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3910 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3911 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3912 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3913 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3914 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3915 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3916 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3917 {
3918 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3919 .name = "Channel Mode",
3920 .info = alc_ch_mode_info,
3921 .get = alc_ch_mode_get,
3922 .put = alc_ch_mode_put,
3923 },
3924 { } /* end */
3925};
3926
Takashi Iwaia9111322011-05-02 11:30:18 +02003927static const struct hda_verb alc880_lg_init_verbs[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003928 /* set capture source to mic-in */
3929 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3930 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3931 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3932 /* mute all amp mixer inputs */
3933 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003934 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3935 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003936 /* line-in to input */
3937 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3938 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3939 /* built-in mic */
3940 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3941 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3942 /* speaker-out */
3943 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3944 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3945 /* mic-in to input */
3946 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3947 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3948 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3949 /* HP-out */
3950 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3951 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3952 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3953 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003954 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003955 { }
3956};
3957
3958/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003959static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003960{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003961 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003962
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003963 spec->autocfg.hp_pins[0] = 0x1b;
3964 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02003965 spec->automute = 1;
3966 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003967}
3968
3969/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003970 * LG LW20
3971 *
3972 * Pin assignment:
3973 * Speaker-out: 0x14
3974 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003975 * Built-in Mic-In: 0x19
3976 * Line-In: 0x1b
3977 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003978 * SPDIF-Out: 0x1e
3979 */
3980
Takashi Iwaia9111322011-05-02 11:30:18 +02003981static const struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003982 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003983 .items = {
3984 { "Mic", 0x0 },
3985 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003986 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003987 },
3988};
3989
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003990#define alc880_lg_lw_modes alc880_threestack_modes
3991
Takashi Iwaia9111322011-05-02 11:30:18 +02003992static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003993 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3994 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3995 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3996 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3997 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3998 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3999 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
4000 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
4001 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4002 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01004003 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4004 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4005 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
4006 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004007 {
4008 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4009 .name = "Channel Mode",
4010 .info = alc_ch_mode_info,
4011 .get = alc_ch_mode_get,
4012 .put = alc_ch_mode_put,
4013 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004014 { } /* end */
4015};
4016
Takashi Iwaia9111322011-05-02 11:30:18 +02004017static const struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004018 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4019 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
4020 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
4021
Takashi Iwaid6815182006-03-23 16:06:23 +01004022 /* set capture source to mic-in */
4023 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4024 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4025 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02004026 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01004027 /* speaker-out */
4028 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4029 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4030 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01004031 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4032 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4033 /* mic-in to input */
4034 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4035 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4036 /* built-in mic */
4037 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4038 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4039 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004040 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01004041 { }
4042};
4043
4044/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004045static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01004046{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004047 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01004048
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004049 spec->autocfg.hp_pins[0] = 0x1b;
4050 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02004051 spec->automute = 1;
4052 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaid6815182006-03-23 16:06:23 +01004053}
4054
Takashi Iwaia9111322011-05-02 11:30:18 +02004055static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004056 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4057 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
4058 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4059 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4060 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
4061 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
4062 { } /* end */
4063};
4064
Takashi Iwaia9111322011-05-02 11:30:18 +02004065static const struct hda_input_mux alc880_medion_rim_capture_source = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004066 .num_items = 2,
4067 .items = {
4068 { "Mic", 0x0 },
4069 { "Internal Mic", 0x1 },
4070 },
4071};
4072
Takashi Iwaia9111322011-05-02 11:30:18 +02004073static const struct hda_verb alc880_medion_rim_init_verbs[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004074 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4075
4076 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4077 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4078
4079 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4080 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4081 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4082 /* Mic2 (as headphone out) for HP output */
4083 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4084 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4085 /* Internal Speaker */
4086 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4087 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4088
4089 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
4090 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
4091
4092 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4093 { }
4094};
4095
4096/* toggle speaker-output according to the hp-jack state */
4097static void alc880_medion_rim_automute(struct hda_codec *codec)
4098{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004099 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02004100 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004101 /* toggle EAPD */
4102 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004103 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
4104 else
4105 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
4106}
4107
4108static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
4109 unsigned int res)
4110{
4111 /* Looks like the unsol event is incompatible with the standard
4112 * definition. 4bit tag is placed at 28 bit!
4113 */
4114 if ((res >> 28) == ALC880_HP_EVENT)
4115 alc880_medion_rim_automute(codec);
4116}
4117
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004118static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004119{
4120 struct alc_spec *spec = codec->spec;
4121
4122 spec->autocfg.hp_pins[0] = 0x14;
4123 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02004124 spec->automute = 1;
4125 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004126}
4127
Takashi Iwaicb53c622007-08-10 17:21:45 +02004128#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02004129static const struct hda_amp_list alc880_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004130 { 0x0b, HDA_INPUT, 0 },
4131 { 0x0b, HDA_INPUT, 1 },
4132 { 0x0b, HDA_INPUT, 2 },
4133 { 0x0b, HDA_INPUT, 3 },
4134 { 0x0b, HDA_INPUT, 4 },
4135 { } /* end */
4136};
4137
Takashi Iwaia9111322011-05-02 11:30:18 +02004138static const struct hda_amp_list alc880_lg_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004139 { 0x0b, HDA_INPUT, 1 },
4140 { 0x0b, HDA_INPUT, 6 },
4141 { 0x0b, HDA_INPUT, 7 },
4142 { } /* end */
4143};
4144#endif
4145
Takashi Iwaid6815182006-03-23 16:06:23 +01004146/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004147 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004148 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004149
Takashi Iwai584c0c42011-03-10 12:51:11 +01004150static void alc_init_special_input_src(struct hda_codec *codec);
4151
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152static int alc_init(struct hda_codec *codec)
4153{
4154 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004155 unsigned int i;
4156
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004157 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004158 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004159
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004160 for (i = 0; i < spec->num_init_verbs; i++)
4161 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai584c0c42011-03-10 12:51:11 +01004162 alc_init_special_input_src(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004163
4164 if (spec->init_hook)
4165 spec->init_hook(codec);
4166
Takashi Iwai58701122011-01-13 15:41:45 +01004167 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
4168
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004169 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 return 0;
4171}
4172
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004173static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
4174{
4175 struct alc_spec *spec = codec->spec;
4176
4177 if (spec->unsol_event)
4178 spec->unsol_event(codec, res);
4179}
4180
Takashi Iwaicb53c622007-08-10 17:21:45 +02004181#ifdef CONFIG_SND_HDA_POWER_SAVE
4182static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
4183{
4184 struct alc_spec *spec = codec->spec;
4185 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
4186}
4187#endif
4188
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189/*
4190 * Analog playback callbacks
4191 */
4192static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
4193 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004194 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195{
4196 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01004197 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
4198 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199}
4200
4201static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4202 struct hda_codec *codec,
4203 unsigned int stream_tag,
4204 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004205 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206{
4207 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004208 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
4209 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210}
4211
4212static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4213 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004214 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215{
4216 struct alc_spec *spec = codec->spec;
4217 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
4218}
4219
4220/*
4221 * Digital out
4222 */
4223static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
4224 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004225 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226{
4227 struct alc_spec *spec = codec->spec;
4228 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
4229}
4230
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004231static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4232 struct hda_codec *codec,
4233 unsigned int stream_tag,
4234 unsigned int format,
4235 struct snd_pcm_substream *substream)
4236{
4237 struct alc_spec *spec = codec->spec;
4238 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
4239 stream_tag, format, substream);
4240}
4241
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004242static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4243 struct hda_codec *codec,
4244 struct snd_pcm_substream *substream)
4245{
4246 struct alc_spec *spec = codec->spec;
4247 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
4248}
4249
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
4251 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004252 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253{
4254 struct alc_spec *spec = codec->spec;
4255 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4256}
4257
4258/*
4259 * Analog capture
4260 */
Takashi Iwai63300792008-01-24 15:31:36 +01004261static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 struct hda_codec *codec,
4263 unsigned int stream_tag,
4264 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004265 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266{
4267 struct alc_spec *spec = codec->spec;
4268
Takashi Iwai63300792008-01-24 15:31:36 +01004269 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 stream_tag, 0, format);
4271 return 0;
4272}
4273
Takashi Iwai63300792008-01-24 15:31:36 +01004274static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01004276 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277{
4278 struct alc_spec *spec = codec->spec;
4279
Takashi Iwai888afa12008-03-18 09:57:50 +01004280 snd_hda_codec_cleanup_stream(codec,
4281 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 return 0;
4283}
4284
Takashi Iwai840b64c2010-07-13 22:49:01 +02004285/* analog capture with dynamic dual-adc changes */
4286static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4287 struct hda_codec *codec,
4288 unsigned int stream_tag,
4289 unsigned int format,
4290 struct snd_pcm_substream *substream)
4291{
4292 struct alc_spec *spec = codec->spec;
4293 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
4294 spec->cur_adc_stream_tag = stream_tag;
4295 spec->cur_adc_format = format;
4296 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
4297 return 0;
4298}
4299
4300static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4301 struct hda_codec *codec,
4302 struct snd_pcm_substream *substream)
4303{
4304 struct alc_spec *spec = codec->spec;
4305 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4306 spec->cur_adc = 0;
4307 return 0;
4308}
4309
Takashi Iwaia9111322011-05-02 11:30:18 +02004310static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02004311 .substreams = 1,
4312 .channels_min = 2,
4313 .channels_max = 2,
4314 .nid = 0, /* fill later */
4315 .ops = {
4316 .prepare = dualmic_capture_pcm_prepare,
4317 .cleanup = dualmic_capture_pcm_cleanup
4318 },
4319};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
4321/*
4322 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004323static const struct hda_pcm_stream alc880_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 .substreams = 1,
4325 .channels_min = 2,
4326 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004327 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 .ops = {
4329 .open = alc880_playback_pcm_open,
4330 .prepare = alc880_playback_pcm_prepare,
4331 .cleanup = alc880_playback_pcm_cleanup
4332 },
4333};
4334
Takashi Iwaia9111322011-05-02 11:30:18 +02004335static const struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004336 .substreams = 1,
4337 .channels_min = 2,
4338 .channels_max = 2,
4339 /* NID is set in alc_build_pcms */
4340};
4341
Takashi Iwaia9111322011-05-02 11:30:18 +02004342static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01004343 .substreams = 1,
4344 .channels_min = 2,
4345 .channels_max = 2,
4346 /* NID is set in alc_build_pcms */
4347};
4348
Takashi Iwaia9111322011-05-02 11:30:18 +02004349static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004350 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 .channels_min = 2,
4352 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004353 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01004355 .prepare = alc880_alt_capture_pcm_prepare,
4356 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 },
4358};
4359
Takashi Iwaia9111322011-05-02 11:30:18 +02004360static const struct hda_pcm_stream alc880_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 .substreams = 1,
4362 .channels_min = 2,
4363 .channels_max = 2,
4364 /* NID is set in alc_build_pcms */
4365 .ops = {
4366 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004367 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004368 .prepare = alc880_dig_playback_pcm_prepare,
4369 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 },
4371};
4372
Takashi Iwaia9111322011-05-02 11:30:18 +02004373static const struct hda_pcm_stream alc880_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 .substreams = 1,
4375 .channels_min = 2,
4376 .channels_max = 2,
4377 /* NID is set in alc_build_pcms */
4378};
4379
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004380/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02004381static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004382 .substreams = 0,
4383 .channels_min = 0,
4384 .channels_max = 0,
4385};
4386
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387static int alc_build_pcms(struct hda_codec *codec)
4388{
4389 struct alc_spec *spec = codec->spec;
4390 struct hda_pcm *info = spec->pcm_rec;
4391 int i;
4392
4393 codec->num_pcms = 1;
4394 codec->pcm_info = info;
4395
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004396 if (spec->no_analog)
4397 goto skip_analog;
4398
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004399 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4400 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004402
Takashi Iwai4a471b72005-12-07 13:56:29 +01004403 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004404 if (snd_BUG_ON(!spec->multiout.dac_nids))
4405 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004406 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
4407 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4408 }
4409 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004410 if (snd_BUG_ON(!spec->adc_nids))
4411 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004412 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
4413 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
Takashi Iwai4a471b72005-12-07 13:56:29 +01004416 if (spec->channel_mode) {
4417 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4418 for (i = 0; i < spec->num_channel_mode; i++) {
4419 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4420 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 }
4423 }
4424
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004425 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004426 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004428 snprintf(spec->stream_name_digital,
4429 sizeof(spec->stream_name_digital),
4430 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004431 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004432 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004433 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004435 if (spec->dig_out_type)
4436 info->pcm_type = spec->dig_out_type;
4437 else
4438 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004439 if (spec->multiout.dig_out_nid &&
4440 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4442 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4443 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004444 if (spec->dig_in_nid &&
4445 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4447 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4448 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004449 /* FIXME: do we need this for all Realtek codec models? */
4450 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 }
4452
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004453 if (spec->no_analog)
4454 return 0;
4455
Takashi Iwaie08a0072006-09-07 17:52:14 +02004456 /* If the use of more than one ADC is requested for the current
4457 * model, configure a second analog capture-only PCM.
4458 */
4459 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004460 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4461 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004462 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004463 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004464 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004465 if (spec->alt_dac_nid) {
4466 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4467 *spec->stream_analog_alt_playback;
4468 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4469 spec->alt_dac_nid;
4470 } else {
4471 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4472 alc_pcm_null_stream;
4473 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4474 }
Raymond Yauce85c9a2011-05-03 13:33:53 +08004475 if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) {
Takashi Iwai63300792008-01-24 15:31:36 +01004476 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4477 *spec->stream_analog_alt_capture;
4478 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4479 spec->adc_nids[1];
4480 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4481 spec->num_adc_nids - 1;
4482 } else {
4483 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4484 alc_pcm_null_stream;
4485 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004486 }
4487 }
4488
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 return 0;
4490}
4491
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004492static inline void alc_shutup(struct hda_codec *codec)
4493{
Takashi Iwai1c7161532011-04-07 10:37:16 +02004494 struct alc_spec *spec = codec->spec;
4495
4496 if (spec && spec->shutup)
4497 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004498 snd_hda_shutup_pins(codec);
4499}
4500
Takashi Iwai603c4012008-07-30 15:01:44 +02004501static void alc_free_kctls(struct hda_codec *codec)
4502{
4503 struct alc_spec *spec = codec->spec;
4504
4505 if (spec->kctls.list) {
4506 struct snd_kcontrol_new *kctl = spec->kctls.list;
4507 int i;
4508 for (i = 0; i < spec->kctls.used; i++)
4509 kfree(kctl[i].name);
4510 }
4511 snd_array_free(&spec->kctls);
4512}
4513
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514static void alc_free(struct hda_codec *codec)
4515{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004516 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004517
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004518 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004519 return;
4520
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004521 alc_shutup(codec);
Takashi Iwaicd372fb2011-03-03 14:40:14 +01004522 snd_hda_input_jack_free(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004523 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004524 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004525 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526}
4527
Hector Martinf5de24b2009-12-20 22:51:31 +01004528#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004529static void alc_power_eapd(struct hda_codec *codec)
4530{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02004531 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004532}
4533
Hector Martinf5de24b2009-12-20 22:51:31 +01004534static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4535{
4536 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004537 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004538 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004539 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004540 return 0;
4541}
4542#endif
4543
Takashi Iwaie044c392008-10-27 16:56:24 +01004544#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004545static int alc_resume(struct hda_codec *codec)
4546{
Takashi Iwai1c7161532011-04-07 10:37:16 +02004547 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01004548 codec->patch_ops.init(codec);
4549 snd_hda_codec_resume_amp(codec);
4550 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004551 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004552 return 0;
4553}
Takashi Iwaie044c392008-10-27 16:56:24 +01004554#endif
4555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556/*
4557 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004558static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 .build_controls = alc_build_controls,
4560 .build_pcms = alc_build_pcms,
4561 .init = alc_init,
4562 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004563 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004564#ifdef SND_HDA_NEEDS_RESUME
4565 .resume = alc_resume,
4566#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004567#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004568 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004569 .check_power_status = alc_check_power_status,
4570#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004571 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572};
4573
Kailang Yangc027ddc2010-03-19 11:33:06 +01004574/* replace the codec chip_name with the given string */
4575static int alc_codec_rename(struct hda_codec *codec, const char *name)
4576{
4577 kfree(codec->chip_name);
4578 codec->chip_name = kstrdup(name, GFP_KERNEL);
4579 if (!codec->chip_name) {
4580 alc_free(codec);
4581 return -ENOMEM;
4582 }
4583 return 0;
4584}
4585
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004586/*
4587 * Test configuration for debugging
4588 *
4589 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4590 * enum controls.
4591 */
4592#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004593static const hda_nid_t alc880_test_dac_nids[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004594 0x02, 0x03, 0x04, 0x05
4595};
4596
Takashi Iwaia9111322011-05-02 11:30:18 +02004597static const struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004598 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004599 .items = {
4600 { "In-1", 0x0 },
4601 { "In-2", 0x1 },
4602 { "In-3", 0x2 },
4603 { "In-4", 0x3 },
4604 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004605 { "Front", 0x5 },
4606 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004607 },
4608};
4609
Takashi Iwaia9111322011-05-02 11:30:18 +02004610static const struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004611 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004612 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004613 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004614 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004615};
4616
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004617static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4618 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004619{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004620 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004621 "N/A", "Line Out", "HP Out",
4622 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4623 };
4624 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4625 uinfo->count = 1;
4626 uinfo->value.enumerated.items = 8;
4627 if (uinfo->value.enumerated.item >= 8)
4628 uinfo->value.enumerated.item = 7;
4629 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4630 return 0;
4631}
4632
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004633static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4634 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004635{
4636 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4637 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4638 unsigned int pin_ctl, item = 0;
4639
4640 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4641 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4642 if (pin_ctl & AC_PINCTL_OUT_EN) {
4643 if (pin_ctl & AC_PINCTL_HP_EN)
4644 item = 2;
4645 else
4646 item = 1;
4647 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4648 switch (pin_ctl & AC_PINCTL_VREFEN) {
4649 case AC_PINCTL_VREF_HIZ: item = 3; break;
4650 case AC_PINCTL_VREF_50: item = 4; break;
4651 case AC_PINCTL_VREF_GRD: item = 5; break;
4652 case AC_PINCTL_VREF_80: item = 6; break;
4653 case AC_PINCTL_VREF_100: item = 7; break;
4654 }
4655 }
4656 ucontrol->value.enumerated.item[0] = item;
4657 return 0;
4658}
4659
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004660static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4661 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004662{
4663 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4664 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004665 static const unsigned int ctls[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004666 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4667 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4668 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4669 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4670 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4671 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4672 };
4673 unsigned int old_ctl, new_ctl;
4674
4675 old_ctl = snd_hda_codec_read(codec, nid, 0,
4676 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4677 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4678 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004679 int val;
4680 snd_hda_codec_write_cache(codec, nid, 0,
4681 AC_VERB_SET_PIN_WIDGET_CONTROL,
4682 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004683 val = ucontrol->value.enumerated.item[0] >= 3 ?
4684 HDA_AMP_MUTE : 0;
4685 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4686 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004687 return 1;
4688 }
4689 return 0;
4690}
4691
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004692static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4693 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004694{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004695 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004696 "Front", "Surround", "CLFE", "Side"
4697 };
4698 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4699 uinfo->count = 1;
4700 uinfo->value.enumerated.items = 4;
4701 if (uinfo->value.enumerated.item >= 4)
4702 uinfo->value.enumerated.item = 3;
4703 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4704 return 0;
4705}
4706
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004707static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4708 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004709{
4710 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4711 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4712 unsigned int sel;
4713
4714 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4715 ucontrol->value.enumerated.item[0] = sel & 3;
4716 return 0;
4717}
4718
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004719static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4720 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004721{
4722 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4723 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4724 unsigned int sel;
4725
4726 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4727 if (ucontrol->value.enumerated.item[0] != sel) {
4728 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004729 snd_hda_codec_write_cache(codec, nid, 0,
4730 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004731 return 1;
4732 }
4733 return 0;
4734}
4735
4736#define PIN_CTL_TEST(xname,nid) { \
4737 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4738 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004739 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004740 .info = alc_test_pin_ctl_info, \
4741 .get = alc_test_pin_ctl_get, \
4742 .put = alc_test_pin_ctl_put, \
4743 .private_value = nid \
4744 }
4745
4746#define PIN_SRC_TEST(xname,nid) { \
4747 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4748 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004749 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004750 .info = alc_test_pin_src_info, \
4751 .get = alc_test_pin_src_get, \
4752 .put = alc_test_pin_src_put, \
4753 .private_value = nid \
4754 }
4755
Takashi Iwaia9111322011-05-02 11:30:18 +02004756static const struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004757 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4758 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4759 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4760 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004761 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4762 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4763 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4764 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004765 PIN_CTL_TEST("Front Pin Mode", 0x14),
4766 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4767 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4768 PIN_CTL_TEST("Side Pin Mode", 0x17),
4769 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4770 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4771 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4772 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4773 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4774 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4775 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4776 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4777 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4778 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4779 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4780 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4781 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4782 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4783 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4784 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4785 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4786 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004787 {
4788 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4789 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004790 .info = alc_ch_mode_info,
4791 .get = alc_ch_mode_get,
4792 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004793 },
4794 { } /* end */
4795};
4796
Takashi Iwaia9111322011-05-02 11:30:18 +02004797static const struct hda_verb alc880_test_init_verbs[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004798 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004799 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4800 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4801 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4802 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4803 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4804 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4805 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4806 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004807 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004808 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4809 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4810 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4811 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004812 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004813 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4814 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4815 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4816 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004817 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004818 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4819 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4820 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4821 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004822 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004823 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4824 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004825 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4826 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4827 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004828 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004829 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4830 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4831 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4832 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004833 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004834 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004835 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004836 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004837 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004838 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004839 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004840 /* Analog input/passthru */
4841 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4842 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4843 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4844 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4845 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004846 { }
4847};
4848#endif
4849
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850/*
4851 */
4852
Takashi Iwaiea734962011-01-17 11:29:34 +01004853static const char * const alc880_models[ALC880_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004854 [ALC880_3ST] = "3stack",
4855 [ALC880_TCL_S700] = "tcl",
4856 [ALC880_3ST_DIG] = "3stack-digout",
4857 [ALC880_CLEVO] = "clevo",
4858 [ALC880_5ST] = "5stack",
4859 [ALC880_5ST_DIG] = "5stack-digout",
4860 [ALC880_W810] = "w810",
4861 [ALC880_Z71V] = "z71v",
4862 [ALC880_6ST] = "6stack",
4863 [ALC880_6ST_DIG] = "6stack-digout",
4864 [ALC880_ASUS] = "asus",
4865 [ALC880_ASUS_W1V] = "asus-w1v",
4866 [ALC880_ASUS_DIG] = "asus-dig",
4867 [ALC880_ASUS_DIG2] = "asus-dig2",
4868 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004869 [ALC880_UNIWILL_P53] = "uniwill-p53",
4870 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004871 [ALC880_F1734] = "F1734",
4872 [ALC880_LG] = "lg",
4873 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004874 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004875#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004876 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004877#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004878 [ALC880_AUTO] = "auto",
4879};
4880
Takashi Iwaia9111322011-05-02 11:30:18 +02004881static const struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004882 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004883 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4884 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4885 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4886 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4887 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4888 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4889 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4890 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004891 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004892 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4893 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4894 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4895 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4896 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4897 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4898 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4899 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4900 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4901 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004902 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004903 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4904 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4905 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004906 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004907 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004908 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4909 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004910 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4911 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004912 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4913 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4914 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4915 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004916 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4917 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004918 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004919 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004920 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Justin P. Mattocka2e2bc22011-02-24 22:16:02 -08004921 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004922 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4923 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004924 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004925 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004926 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004927 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004928 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004929 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004930 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004931 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004932 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004933 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05004934 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004935 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004936 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004937 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4938 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4939 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4940 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004941 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4942 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004943 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004944 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004945 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4946 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004947 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4948 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4949 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004950 /* default Intel */
4951 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004952 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4953 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 {}
4955};
4956
Takashi Iwai16ded522005-06-10 19:58:24 +02004957/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004958 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004959 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004960static const struct alc_config_preset alc880_presets[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02004961 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004962 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004963 .init_verbs = { alc880_volume_init_verbs,
4964 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004965 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004966 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004967 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4968 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004969 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004970 .input_mux = &alc880_capture_source,
4971 },
4972 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004973 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004974 .init_verbs = { alc880_volume_init_verbs,
4975 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004976 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004977 .dac_nids = alc880_dac_nids,
4978 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004979 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4980 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004981 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004982 .input_mux = &alc880_capture_source,
4983 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004984 [ALC880_TCL_S700] = {
4985 .mixers = { alc880_tcl_s700_mixer },
4986 .init_verbs = { alc880_volume_init_verbs,
4987 alc880_pin_tcl_S700_init_verbs,
4988 alc880_gpio2_init_verbs },
4989 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4990 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004991 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4992 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004993 .hp_nid = 0x03,
4994 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4995 .channel_mode = alc880_2_jack_modes,
4996 .input_mux = &alc880_capture_source,
4997 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004998 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004999 .mixers = { alc880_three_stack_mixer,
5000 alc880_five_stack_mixer},
5001 .init_verbs = { alc880_volume_init_verbs,
5002 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005003 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5004 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005005 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5006 .channel_mode = alc880_fivestack_modes,
5007 .input_mux = &alc880_capture_source,
5008 },
5009 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005010 .mixers = { alc880_three_stack_mixer,
5011 alc880_five_stack_mixer },
5012 .init_verbs = { alc880_volume_init_verbs,
5013 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005014 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5015 .dac_nids = alc880_dac_nids,
5016 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005017 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5018 .channel_mode = alc880_fivestack_modes,
5019 .input_mux = &alc880_capture_source,
5020 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005021 [ALC880_6ST] = {
5022 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005023 .init_verbs = { alc880_volume_init_verbs,
5024 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005025 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5026 .dac_nids = alc880_6st_dac_nids,
5027 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5028 .channel_mode = alc880_sixstack_modes,
5029 .input_mux = &alc880_6stack_capture_source,
5030 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005031 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005032 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005033 .init_verbs = { alc880_volume_init_verbs,
5034 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005035 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5036 .dac_nids = alc880_6st_dac_nids,
5037 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005038 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5039 .channel_mode = alc880_sixstack_modes,
5040 .input_mux = &alc880_6stack_capture_source,
5041 },
5042 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005043 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005044 .init_verbs = { alc880_volume_init_verbs,
5045 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005046 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005047 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
5048 .dac_nids = alc880_w810_dac_nids,
5049 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005050 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
5051 .channel_mode = alc880_w810_modes,
5052 .input_mux = &alc880_capture_source,
5053 },
5054 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005055 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005056 .init_verbs = { alc880_volume_init_verbs,
5057 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005058 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
5059 .dac_nids = alc880_z71v_dac_nids,
5060 .dig_out_nid = ALC880_DIGOUT_NID,
5061 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005062 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5063 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02005064 .input_mux = &alc880_capture_source,
5065 },
5066 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005067 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005068 .init_verbs = { alc880_volume_init_verbs,
5069 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005070 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
5071 .dac_nids = alc880_f1734_dac_nids,
5072 .hp_nid = 0x02,
5073 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5074 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01005075 .input_mux = &alc880_f1734_capture_source,
5076 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005077 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005078 .init_hook = alc_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02005079 },
5080 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005081 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005082 .init_verbs = { alc880_volume_init_verbs,
5083 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005084 alc880_gpio1_init_verbs },
5085 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5086 .dac_nids = alc880_asus_dac_nids,
5087 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5088 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005089 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005090 .input_mux = &alc880_capture_source,
5091 },
5092 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005093 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005094 .init_verbs = { alc880_volume_init_verbs,
5095 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005096 alc880_gpio1_init_verbs },
5097 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5098 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005099 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005100 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5101 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005102 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005103 .input_mux = &alc880_capture_source,
5104 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005105 [ALC880_ASUS_DIG2] = {
5106 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005107 .init_verbs = { alc880_volume_init_verbs,
5108 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01005109 alc880_gpio2_init_verbs }, /* use GPIO2 */
5110 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5111 .dac_nids = alc880_asus_dac_nids,
5112 .dig_out_nid = ALC880_DIGOUT_NID,
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,
Kailang Yangdf694da2005-12-05 19:42:22 +01005116 .input_mux = &alc880_capture_source,
5117 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005118 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005119 .mixers = { alc880_asus_mixer, alc880_asus_w1v_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 },
5131 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005132 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02005133 .init_verbs = { alc880_volume_init_verbs,
5134 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005135 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5136 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005137 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005138 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5139 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005140 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005141 .input_mux = &alc880_capture_source,
5142 },
Kailang Yangccc656c2006-10-17 12:32:26 +02005143 [ALC880_UNIWILL] = {
5144 .mixers = { alc880_uniwill_mixer },
5145 .init_verbs = { alc880_volume_init_verbs,
5146 alc880_uniwill_init_verbs },
5147 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5148 .dac_nids = alc880_asus_dac_nids,
5149 .dig_out_nid = ALC880_DIGOUT_NID,
5150 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5151 .channel_mode = alc880_threestack_modes,
5152 .need_dac_fix = 1,
5153 .input_mux = &alc880_capture_source,
5154 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005155 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02005156 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02005157 },
5158 [ALC880_UNIWILL_P53] = {
5159 .mixers = { alc880_uniwill_p53_mixer },
5160 .init_verbs = { alc880_volume_init_verbs,
5161 alc880_uniwill_p53_init_verbs },
5162 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5163 .dac_nids = alc880_asus_dac_nids,
5164 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005165 .channel_mode = alc880_threestack_modes,
5166 .input_mux = &alc880_capture_source,
5167 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005168 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005169 .init_hook = alc_hp_automute,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005170 },
5171 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005172 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005173 .init_verbs = { alc880_volume_init_verbs,
5174 alc880_uniwill_p53_init_verbs,
5175 alc880_beep_init_verbs },
5176 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5177 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02005178 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005179 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5180 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02005181 .input_mux = &alc880_capture_source,
5182 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005183 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005184 .init_hook = alc_hp_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02005185 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005186 [ALC880_CLEVO] = {
5187 .mixers = { alc880_three_stack_mixer },
5188 .init_verbs = { alc880_volume_init_verbs,
5189 alc880_pin_clevo_init_verbs },
5190 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5191 .dac_nids = alc880_dac_nids,
5192 .hp_nid = 0x03,
5193 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5194 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005195 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005196 .input_mux = &alc880_capture_source,
5197 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005198 [ALC880_LG] = {
5199 .mixers = { alc880_lg_mixer },
5200 .init_verbs = { alc880_volume_init_verbs,
5201 alc880_lg_init_verbs },
5202 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
5203 .dac_nids = alc880_lg_dac_nids,
5204 .dig_out_nid = ALC880_DIGOUT_NID,
5205 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
5206 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005207 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005208 .input_mux = &alc880_lg_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005209 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005210 .setup = alc880_lg_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005211 .init_hook = alc_hp_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005212#ifdef CONFIG_SND_HDA_POWER_SAVE
5213 .loopbacks = alc880_lg_loopbacks,
5214#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005215 },
Takashi Iwaid6815182006-03-23 16:06:23 +01005216 [ALC880_LG_LW] = {
5217 .mixers = { alc880_lg_lw_mixer },
5218 .init_verbs = { alc880_volume_init_verbs,
5219 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005220 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01005221 .dac_nids = alc880_dac_nids,
5222 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005223 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
5224 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01005225 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005226 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005227 .setup = alc880_lg_lw_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005228 .init_hook = alc_hp_automute,
Takashi Iwaid6815182006-03-23 16:06:23 +01005229 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005230 [ALC880_MEDION_RIM] = {
5231 .mixers = { alc880_medion_rim_mixer },
5232 .init_verbs = { alc880_volume_init_verbs,
5233 alc880_medion_rim_init_verbs,
5234 alc_gpio2_init_verbs },
5235 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5236 .dac_nids = alc880_dac_nids,
5237 .dig_out_nid = ALC880_DIGOUT_NID,
5238 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5239 .channel_mode = alc880_2_jack_modes,
5240 .input_mux = &alc880_medion_rim_capture_source,
5241 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005242 .setup = alc880_medion_rim_setup,
5243 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005244 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005245#ifdef CONFIG_SND_DEBUG
5246 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005247 .mixers = { alc880_test_mixer },
5248 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005249 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
5250 .dac_nids = alc880_test_dac_nids,
5251 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005252 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
5253 .channel_mode = alc880_test_modes,
5254 .input_mux = &alc880_test_capture_source,
5255 },
5256#endif
5257};
5258
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005259/*
5260 * Automatic parse of I/O pins from the BIOS configuration
5261 */
5262
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005263enum {
5264 ALC_CTL_WIDGET_VOL,
5265 ALC_CTL_WIDGET_MUTE,
5266 ALC_CTL_BIND_MUTE,
5267};
Takashi Iwaia9111322011-05-02 11:30:18 +02005268static const struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005269 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
5270 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01005271 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005272};
5273
Takashi Iwaice764ab2011-04-27 16:35:23 +02005274static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
5275{
5276 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
5277 return snd_array_new(&spec->kctls);
5278}
5279
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005280/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005281static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005282 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005283{
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01005284 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005285
Takashi Iwaice764ab2011-04-27 16:35:23 +02005286 knew = alc_kcontrol_new(spec);
Takashi Iwai603c4012008-07-30 15:01:44 +02005287 if (!knew)
5288 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005289 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07005290 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005291 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005292 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005293 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01005294 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01005295 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005296 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005297 return 0;
5298}
5299
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005300static int add_control_with_pfx(struct alc_spec *spec, int type,
5301 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005302 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005303{
5304 char name[32];
5305 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005306 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005307}
5308
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005309#define add_pb_vol_ctrl(spec, type, pfx, val) \
5310 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5311#define add_pb_sw_ctrl(spec, type, pfx, val) \
5312 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5313#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5314 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5315#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5316 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005317
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005318#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5319#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5320#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5321#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005322#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5323#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5324#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5325#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5326#define ALC880_PIN_CD_NID 0x1c
5327
Takashi Iwai6843ca12011-06-24 11:03:58 +02005328static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
5329 bool can_be_master, int *index)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005330{
Takashi Iwaice764ab2011-04-27 16:35:23 +02005331 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai6843ca12011-06-24 11:03:58 +02005332 static const char * const chname[4] = {
5333 "Front", "Surround", NULL /*CLFE*/, "Side"
5334 };
Takashi Iwaice764ab2011-04-27 16:35:23 +02005335
Takashi Iwai6843ca12011-06-24 11:03:58 +02005336 *index = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02005337 if (cfg->line_outs == 1 && !spec->multi_ios &&
5338 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005339 return "Master";
5340
5341 switch (cfg->line_out_type) {
5342 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01005343 if (cfg->line_outs == 1)
5344 return "Speaker";
5345 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005346 case AUTO_PIN_HP_OUT:
Takashi Iwai6843ca12011-06-24 11:03:58 +02005347 /* for multi-io case, only the primary out */
5348 if (ch && spec->multi_ios)
5349 break;
5350 *index = ch;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005351 return "Headphone";
5352 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02005353 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005354 return "PCM";
5355 break;
5356 }
Takashi Iwai6843ca12011-06-24 11:03:58 +02005357 return chname[ch];
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005358}
5359
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005360/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005361static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005362 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005363 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005364{
Kailang Yangdf694da2005-12-05 19:42:22 +01005365 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005366
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005367 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005368 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5369 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005370 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005371 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005372 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5373 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005374 return err;
5375 return 0;
5376}
5377
Takashi Iwai05f5f472009-08-25 13:10:18 +02005378static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005379{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005380 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5381 return (pincap & AC_PINCAP_IN) != 0;
5382}
5383
5384/* create playback/capture controls for input pins */
5385static int alc_auto_create_input_ctls(struct hda_codec *codec,
5386 const struct auto_pin_cfg *cfg,
5387 hda_nid_t mixer,
5388 hda_nid_t cap1, hda_nid_t cap2)
5389{
5390 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005391 struct hda_input_mux *imux = &spec->private_imux[0];
David Henningsson5322bf22011-01-05 11:03:56 +01005392 int i, err, idx, type_idx = 0;
5393 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005394
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005395 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005396 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005397 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005398
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005399 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005400 if (!alc_is_input_pin(codec, pin))
5401 continue;
5402
David Henningsson5322bf22011-01-05 11:03:56 +01005403 label = hda_get_autocfg_input_label(codec, cfg, i);
5404 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005405 type_idx++;
5406 else
5407 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005408 prev_label = label;
5409
Takashi Iwai05f5f472009-08-25 13:10:18 +02005410 if (mixer) {
5411 idx = get_connection_index(codec, mixer, pin);
5412 if (idx >= 0) {
5413 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005414 label, type_idx,
5415 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005416 if (err < 0)
5417 return err;
5418 }
5419 }
5420
5421 if (!cap1)
5422 continue;
5423 idx = get_connection_index(codec, cap1, pin);
5424 if (idx < 0 && cap2)
5425 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005426 if (idx >= 0)
5427 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005428 }
5429 return 0;
5430}
5431
Takashi Iwai343a04b2011-07-06 14:28:39 +02005432static int alc_auto_fill_dac_nids(struct hda_codec *codec);
5433static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
5434 const struct auto_pin_cfg *cfg);
5435static int alc_auto_create_hp_out(struct hda_codec *codec);
5436static int alc_auto_create_speaker_out(struct hda_codec *codec);
5437static void alc_auto_init_multi_out(struct hda_codec *codec);
5438static void alc_auto_init_extra_out(struct hda_codec *codec);
5439
Takashi Iwai05f5f472009-08-25 13:10:18 +02005440static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5441 const struct auto_pin_cfg *cfg)
5442{
5443 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5444}
5445
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005446static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5447 unsigned int pin_type)
5448{
5449 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5450 pin_type);
5451 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005452 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5453 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005454}
5455
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005456static int get_pin_type(int line_out_type)
5457{
5458 if (line_out_type == AUTO_PIN_HP_OUT)
5459 return PIN_HP;
5460 else
5461 return PIN_OUT;
5462}
5463
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005464static void alc880_auto_init_analog_input(struct hda_codec *codec)
5465{
5466 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005467 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005468 int i;
5469
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005470 for (i = 0; i < cfg->num_inputs; i++) {
5471 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005472 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005473 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005474 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005475 snd_hda_codec_write(codec, nid, 0,
5476 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005477 AMP_OUT_MUTE);
5478 }
5479 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005480
5481 /* mute all loopback inputs */
5482 if (spec->mixer_nid) {
5483 int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
5484 for (i = 0; i < nums; i++)
5485 snd_hda_codec_write(codec, spec->mixer_nid, 0,
5486 AC_VERB_SET_AMP_GAIN_MUTE,
5487 AMP_IN_MUTE(i));
5488 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005489}
5490
Takashi Iwai7f311a42010-04-09 17:32:23 +02005491static void alc880_auto_init_input_src(struct hda_codec *codec)
5492{
5493 struct alc_spec *spec = codec->spec;
5494 int c;
5495
5496 for (c = 0; c < spec->num_adc_nids; c++) {
5497 unsigned int mux_idx;
5498 const struct hda_input_mux *imux;
5499 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5500 imux = &spec->input_mux[mux_idx];
5501 if (!imux->num_items && mux_idx > 0)
5502 imux = &spec->input_mux[0];
5503 if (imux)
5504 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5505 AC_VERB_SET_CONNECT_SEL,
5506 imux->items[0].index);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005507 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5508 AC_VERB_SET_AMP_GAIN_MUTE,
5509 AMP_IN_MUTE(0));
Takashi Iwai7f311a42010-04-09 17:32:23 +02005510 }
5511}
5512
Takashi Iwaicb053a82011-06-27 11:32:07 +02005513static int alc_auto_add_multi_channel_mode(struct hda_codec *codec,
5514 int (*fill_dac)(struct hda_codec *));
Takashi Iwaice764ab2011-04-27 16:35:23 +02005515
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005516/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005517/* return 1 if successful, 0 if the proper config is not found,
5518 * or a negative error code
5519 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005520static int alc880_parse_auto_config(struct hda_codec *codec)
5521{
5522 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005523 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005524 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005525
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005526 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5527 alc880_ignore);
5528 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005529 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005530 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005531 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005532
Takashi Iwai343a04b2011-07-06 14:28:39 +02005533 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005534 if (err < 0)
5535 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005536 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +02005537 if (err < 0)
5538 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005539 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005540 if (err < 0)
5541 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005542 err = alc_auto_create_hp_out(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005543 if (err < 0)
5544 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005545 err = alc_auto_create_speaker_out(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005546 if (err < 0)
5547 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005548 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005549 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005550 return err;
5551
5552 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5553
Takashi Iwai757899a2010-07-30 10:48:14 +02005554 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005555
Takashi Iwai603c4012008-07-30 15:01:44 +02005556 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005557 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005558
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005559 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005560 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005561
Kailang Yang6227cdc2010-02-25 08:36:52 +01005562 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005563
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005564 return 1;
5565}
5566
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005567/* additional initialization for auto-configuration model */
5568static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005569{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005570 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005571 alc_auto_init_multi_out(codec);
5572 alc_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005573 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005574 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005575 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005576 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005577 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005578}
5579
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005580/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5581 * one of two digital mic pins, e.g. on ALC272
5582 */
5583static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005584{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005585 struct alc_spec *spec = codec->spec;
5586 int i;
5587
5588 for (i = 0; i < spec->num_adc_nids; i++) {
5589 hda_nid_t cap = spec->capsrc_nids ?
5590 spec->capsrc_nids[i] : spec->adc_nids[i];
5591 int iidx, eidx;
5592
5593 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5594 if (iidx < 0)
5595 continue;
5596 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5597 if (eidx < 0)
5598 continue;
5599 spec->int_mic.mux_idx = iidx;
5600 spec->ext_mic.mux_idx = eidx;
5601 if (spec->capsrc_nids)
5602 spec->capsrc_nids += i;
5603 spec->adc_nids += i;
5604 spec->num_adc_nids = 1;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005605 /* optional dock-mic */
5606 eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
5607 if (eidx < 0)
5608 spec->dock_mic.pin = 0;
5609 else
5610 spec->dock_mic.mux_idx = eidx;
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005611 return;
5612 }
5613 snd_printd(KERN_INFO "hda_codec: %s: "
5614 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5615 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5616 spec->auto_mic = 0; /* disable auto-mic to be sure */
5617}
5618
Takashi Iwai748cce42010-08-04 07:37:39 +02005619/* select or unmute the given capsrc route */
5620static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5621 int idx)
5622{
5623 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5624 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5625 HDA_AMP_MUTE, 0);
5626 } else {
5627 snd_hda_codec_write_cache(codec, cap, 0,
5628 AC_VERB_SET_CONNECT_SEL, idx);
5629 }
5630}
5631
Takashi Iwai840b64c2010-07-13 22:49:01 +02005632/* set the default connection to that pin */
5633static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5634{
5635 struct alc_spec *spec = codec->spec;
5636 int i;
5637
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005638 if (!pin)
5639 return 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005640 for (i = 0; i < spec->num_adc_nids; i++) {
5641 hda_nid_t cap = spec->capsrc_nids ?
5642 spec->capsrc_nids[i] : spec->adc_nids[i];
5643 int idx;
5644
5645 idx = get_connection_index(codec, cap, pin);
5646 if (idx < 0)
5647 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005648 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005649 return i; /* return the found index */
5650 }
5651 return -1; /* not found */
5652}
5653
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005654/* choose the ADC/MUX containing the input pin and initialize the setup */
5655static void fixup_single_adc(struct hda_codec *codec)
5656{
5657 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005658 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005659 int i;
5660
5661 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005662 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005663 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005664 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005665 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005666 /* use only this ADC */
5667 if (spec->capsrc_nids)
5668 spec->capsrc_nids += i;
5669 spec->adc_nids += i;
5670 spec->num_adc_nids = 1;
Takashi Iwai584c0c42011-03-10 12:51:11 +01005671 spec->single_input_src = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005672 }
5673}
5674
Takashi Iwai840b64c2010-07-13 22:49:01 +02005675/* initialize dual adcs */
5676static void fixup_dual_adc_switch(struct hda_codec *codec)
5677{
5678 struct alc_spec *spec = codec->spec;
5679 init_capsrc_for_pin(codec, spec->ext_mic.pin);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005680 init_capsrc_for_pin(codec, spec->dock_mic.pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005681 init_capsrc_for_pin(codec, spec->int_mic.pin);
5682}
5683
Takashi Iwai584c0c42011-03-10 12:51:11 +01005684/* initialize some special cases for input sources */
5685static void alc_init_special_input_src(struct hda_codec *codec)
5686{
5687 struct alc_spec *spec = codec->spec;
5688 if (spec->dual_adc_switch)
5689 fixup_dual_adc_switch(codec);
5690 else if (spec->single_input_src)
5691 init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
5692}
5693
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005694static void set_capture_mixer(struct hda_codec *codec)
5695{
5696 struct alc_spec *spec = codec->spec;
Takashi Iwaia9111322011-05-02 11:30:18 +02005697 static const struct snd_kcontrol_new *caps[2][3] = {
Takashi Iwaia23b6882009-03-23 15:21:36 +01005698 { alc_capture_mixer_nosrc1,
5699 alc_capture_mixer_nosrc2,
5700 alc_capture_mixer_nosrc3 },
5701 { alc_capture_mixer1,
5702 alc_capture_mixer2,
5703 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005704 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005705 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005706 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005707 int num_adcs = spec->num_adc_nids;
5708 if (spec->dual_adc_switch)
Takashi Iwai584c0c42011-03-10 12:51:11 +01005709 num_adcs = 1;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005710 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005711 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005712 else if (spec->input_mux) {
5713 if (spec->input_mux->num_items > 1)
5714 mux = 1;
5715 else if (spec->input_mux->num_items == 1)
5716 fixup_single_adc(codec);
5717 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005718 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005719 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005720}
5721
Takashi Iwai66946352010-03-29 17:21:45 +02005722/* fill adc_nids (and capsrc_nids) containing all active input pins */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005723static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids,
Takashi Iwai66946352010-03-29 17:21:45 +02005724 int num_nids)
5725{
5726 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005727 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005728 int n;
5729 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5730
5731 for (n = 0; n < num_nids; n++) {
5732 hda_nid_t adc, cap;
5733 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5734 int nconns, i, j;
5735
5736 adc = nids[n];
5737 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5738 continue;
5739 cap = adc;
5740 nconns = snd_hda_get_connections(codec, cap, conn,
5741 ARRAY_SIZE(conn));
5742 if (nconns == 1) {
5743 cap = conn[0];
5744 nconns = snd_hda_get_connections(codec, cap, conn,
5745 ARRAY_SIZE(conn));
5746 }
5747 if (nconns <= 0)
5748 continue;
5749 if (!fallback_adc) {
5750 fallback_adc = adc;
5751 fallback_cap = cap;
5752 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005753 for (i = 0; i < cfg->num_inputs; i++) {
5754 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005755 for (j = 0; j < nconns; j++) {
5756 if (conn[j] == nid)
5757 break;
5758 }
5759 if (j >= nconns)
5760 break;
5761 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005762 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005763 int num_adcs = spec->num_adc_nids;
5764 spec->private_adc_nids[num_adcs] = adc;
5765 spec->private_capsrc_nids[num_adcs] = cap;
5766 spec->num_adc_nids++;
5767 spec->adc_nids = spec->private_adc_nids;
5768 if (adc != cap)
5769 spec->capsrc_nids = spec->private_capsrc_nids;
5770 }
5771 }
5772 if (!spec->num_adc_nids) {
5773 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005774 " using fallback 0x%x\n",
5775 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005776 spec->private_adc_nids[0] = fallback_adc;
5777 spec->adc_nids = spec->private_adc_nids;
5778 if (fallback_adc != fallback_cap) {
5779 spec->private_capsrc_nids[0] = fallback_cap;
5780 spec->capsrc_nids = spec->private_adc_nids;
5781 }
5782 }
5783}
5784
Takashi Iwai67d634c2009-11-16 15:35:59 +01005785#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005786#define set_beep_amp(spec, nid, idx, dir) \
5787 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005788
Takashi Iwaia9111322011-05-02 11:30:18 +02005789static const struct snd_pci_quirk beep_white_list[] = {
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005790 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005791 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Daniel Corderoa7e985e2011-04-29 08:18:06 +02005792 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
Madis Janson39dfe132011-05-19 18:32:41 +02005793 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005794 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005795 {}
5796};
5797
5798static inline int has_cdefine_beep(struct hda_codec *codec)
5799{
5800 struct alc_spec *spec = codec->spec;
5801 const struct snd_pci_quirk *q;
5802 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5803 if (q)
5804 return q->value;
5805 return spec->cdefine.enable_pcbeep;
5806}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005807#else
5808#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005809#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005810#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005811
5812/*
5813 * OK, here we have finally the patch for ALC880
5814 */
5815
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816static int patch_alc880(struct hda_codec *codec)
5817{
5818 struct alc_spec *spec;
5819 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005820 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005822 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 if (spec == NULL)
5824 return -ENOMEM;
5825
5826 codec->spec = spec;
5827
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005828 spec->mixer_nid = 0x0b;
5829
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005830 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5831 alc880_models,
5832 alc880_cfg_tbl);
5833 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005834 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5835 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005836 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 }
5838
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005839 if (board_config == ALC880_AUTO) {
5840 /* automatic parse from the BIOS config */
5841 err = alc880_parse_auto_config(codec);
5842 if (err < 0) {
5843 alc_free(codec);
5844 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005845 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005846 printk(KERN_INFO
5847 "hda_codec: Cannot set up configuration "
5848 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005849 board_config = ALC880_3ST;
5850 }
5851 }
5852
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005853 err = snd_hda_attach_beep_device(codec, 0x1);
5854 if (err < 0) {
5855 alc_free(codec);
5856 return err;
5857 }
5858
Kailang Yangdf694da2005-12-05 19:42:22 +01005859 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005860 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5863 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005864 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5867 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5868
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005869 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005870 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005871 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005872 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005873 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005874 if (wcap != AC_WID_AUD_IN) {
5875 spec->adc_nids = alc880_adc_nids_alt;
5876 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005877 } else {
5878 spec->adc_nids = alc880_adc_nids;
5879 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005880 }
5881 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005882 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005883 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884
Takashi Iwai2134ea42008-01-10 16:53:55 +01005885 spec->vmaster_nid = 0x0c;
5886
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005888 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005889 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005890#ifdef CONFIG_SND_HDA_POWER_SAVE
5891 if (!spec->loopback.amplist)
5892 spec->loopback.amplist = alc880_loopbacks;
5893#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894
5895 return 0;
5896}
5897
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005898
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899/*
5900 * ALC260 support
5901 */
5902
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005903static const hda_nid_t alc260_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005904 /* front */
5905 0x02,
5906};
5907
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005908static const hda_nid_t alc260_adc_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005909 /* ADC0 */
5910 0x04,
5911};
5912
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005913static const hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005914 /* ADC1 */
5915 0x05,
5916};
5917
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005918/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5919 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5920 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005921static const hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005922 /* ADC0, ADC1 */
5923 0x04, 0x05
5924};
5925
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005926#define ALC260_DIGOUT_NID 0x03
5927#define ALC260_DIGIN_NID 0x06
5928
Takashi Iwaia9111322011-05-02 11:30:18 +02005929static const struct hda_input_mux alc260_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005930 .num_items = 4,
5931 .items = {
5932 { "Mic", 0x0 },
5933 { "Front Mic", 0x1 },
5934 { "Line", 0x2 },
5935 { "CD", 0x4 },
5936 },
5937};
5938
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005939/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005940 * headphone jack and the internal CD lines since these are the only pins at
5941 * which audio can appear. For flexibility, also allow the option of
5942 * recording the mixer output on the second ADC (ADC0 doesn't have a
5943 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005944 */
Takashi Iwaia9111322011-05-02 11:30:18 +02005945static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005946 {
5947 .num_items = 3,
5948 .items = {
5949 { "Mic/Line", 0x0 },
5950 { "CD", 0x4 },
5951 { "Headphone", 0x2 },
5952 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005953 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005954 {
5955 .num_items = 4,
5956 .items = {
5957 { "Mic/Line", 0x0 },
5958 { "CD", 0x4 },
5959 { "Headphone", 0x2 },
5960 { "Mixer", 0x5 },
5961 },
5962 },
5963
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005964};
5965
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005966/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5967 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005968 */
Takashi Iwaia9111322011-05-02 11:30:18 +02005969static const struct hda_input_mux alc260_acer_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005970 {
5971 .num_items = 4,
5972 .items = {
5973 { "Mic", 0x0 },
5974 { "Line", 0x2 },
5975 { "CD", 0x4 },
5976 { "Headphone", 0x5 },
5977 },
5978 },
5979 {
5980 .num_items = 5,
5981 .items = {
5982 { "Mic", 0x0 },
5983 { "Line", 0x2 },
5984 { "CD", 0x4 },
5985 { "Headphone", 0x6 },
5986 { "Mixer", 0x5 },
5987 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005988 },
5989};
Michael Schwingencc959482009-02-22 18:58:45 +01005990
5991/* Maxdata Favorit 100XS */
Takashi Iwaia9111322011-05-02 11:30:18 +02005992static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
Michael Schwingencc959482009-02-22 18:58:45 +01005993 {
5994 .num_items = 2,
5995 .items = {
5996 { "Line/Mic", 0x0 },
5997 { "CD", 0x4 },
5998 },
5999 },
6000 {
6001 .num_items = 3,
6002 .items = {
6003 { "Line/Mic", 0x0 },
6004 { "CD", 0x4 },
6005 { "Mixer", 0x5 },
6006 },
6007 },
6008};
6009
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010/*
6011 * This is just place-holder, so there's something for alc_build_pcms to look
6012 * at when it calculates the maximum number of channels. ALC260 has no mixer
6013 * element which allows changing the channel mode, so the verb list is
6014 * never used.
6015 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006016static const struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 { 2, NULL },
6018};
6019
Kailang Yangdf694da2005-12-05 19:42:22 +01006020
6021/* Mixer combinations
6022 *
6023 * basic: base_output + input + pc_beep + capture
6024 * HP: base_output + input + capture_alt
6025 * HP_3013: hp_3013 + input + capture
6026 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006027 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01006028 */
6029
Takashi Iwaia9111322011-05-02 11:30:18 +02006030static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006031 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006032 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006033 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6034 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6035 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6036 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6037 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006038};
Kailang Yangdf694da2005-12-05 19:42:22 +01006039
Takashi Iwaia9111322011-05-02 11:30:18 +02006040static const struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6042 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6043 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6044 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6045 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6046 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6047 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
6048 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 { } /* end */
6050};
6051
Takashi Iwaibec15c32008-01-28 18:16:30 +01006052/* update HP, line and mono out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +02006053static void alc260_hp_master_update(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006054{
Takashi Iwaie9427962011-04-28 15:46:07 +02006055 update_speakers(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006056}
6057
6058static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
6059 struct snd_ctl_elem_value *ucontrol)
6060{
6061 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6062 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006063 *ucontrol->value.integer.value = !spec->master_mute;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006064 return 0;
6065}
6066
6067static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
6068 struct snd_ctl_elem_value *ucontrol)
6069{
6070 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6071 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006072 int val = !*ucontrol->value.integer.value;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006073
Takashi Iwaie9427962011-04-28 15:46:07 +02006074 if (val == spec->master_mute)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006075 return 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02006076 spec->master_mute = val;
6077 alc260_hp_master_update(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006078 return 1;
6079}
6080
Takashi Iwaia9111322011-05-02 11:30:18 +02006081static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006082 {
6083 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6084 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006085 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006086 .info = snd_ctl_boolean_mono_info,
6087 .get = alc260_hp_master_sw_get,
6088 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006089 },
6090 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6091 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
6092 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6093 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6094 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
6095 HDA_OUTPUT),
6096 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6097 { } /* end */
6098};
6099
Takashi Iwaia9111322011-05-02 11:30:18 +02006100static const struct hda_verb alc260_hp_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006101 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6102 {},
6103};
6104
Takashi Iwaie9427962011-04-28 15:46:07 +02006105static void alc260_hp_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006106{
6107 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006108
Takashi Iwaie9427962011-04-28 15:46:07 +02006109 spec->autocfg.hp_pins[0] = 0x0f;
6110 spec->autocfg.speaker_pins[0] = 0x10;
6111 spec->autocfg.speaker_pins[1] = 0x11;
6112 spec->automute = 1;
6113 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006114}
6115
Takashi Iwaia9111322011-05-02 11:30:18 +02006116static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006117 {
6118 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6119 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006120 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006121 .info = snd_ctl_boolean_mono_info,
6122 .get = alc260_hp_master_sw_get,
6123 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006124 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006125 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6126 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6127 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
6128 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
6129 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6130 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006131 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6132 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02006133 { } /* end */
6134};
6135
Takashi Iwaie9427962011-04-28 15:46:07 +02006136static void alc260_hp_3013_setup(struct hda_codec *codec)
6137{
6138 struct alc_spec *spec = codec->spec;
6139
6140 spec->autocfg.hp_pins[0] = 0x15;
6141 spec->autocfg.speaker_pins[0] = 0x10;
6142 spec->autocfg.speaker_pins[1] = 0x11;
6143 spec->automute = 1;
6144 spec->automute_mode = ALC_AUTOMUTE_PIN;
6145}
6146
Takashi Iwaia9111322011-05-02 11:30:18 +02006147static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
Kailang Yang3f878302008-08-26 13:02:23 +02006148 .ops = &snd_hda_bind_vol,
6149 .values = {
6150 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
6151 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
6152 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
6153 0
6154 },
6155};
6156
Takashi Iwaia9111322011-05-02 11:30:18 +02006157static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
Kailang Yang3f878302008-08-26 13:02:23 +02006158 .ops = &snd_hda_bind_sw,
6159 .values = {
6160 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
6161 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
6162 0
6163 },
6164};
6165
Takashi Iwaia9111322011-05-02 11:30:18 +02006166static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006167 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
6168 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
6169 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
6170 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6171 { } /* end */
6172};
6173
Takashi Iwaia9111322011-05-02 11:30:18 +02006174static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006175 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6176 {},
6177};
6178
Takashi Iwaie9427962011-04-28 15:46:07 +02006179static void alc260_hp_3012_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006180{
6181 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006182
Takashi Iwaie9427962011-04-28 15:46:07 +02006183 spec->autocfg.hp_pins[0] = 0x10;
6184 spec->autocfg.speaker_pins[0] = 0x0f;
6185 spec->autocfg.speaker_pins[1] = 0x11;
6186 spec->autocfg.speaker_pins[2] = 0x15;
6187 spec->automute = 1;
6188 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang3f878302008-08-26 13:02:23 +02006189}
6190
6191/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006192 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6193 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006194static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006195 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006196 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006197 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006198 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6199 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6200 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6201 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006202 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006203 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6204 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006205 { } /* end */
6206};
6207
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006208/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6209 * versions of the ALC260 don't act on requests to enable mic bias from NID
6210 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6211 * datasheet doesn't mention this restriction. At this stage it's not clear
6212 * whether this behaviour is intentional or is a hardware bug in chip
6213 * revisions available in early 2006. Therefore for now allow the
6214 * "Headphone Jack Mode" control to span all choices, but if it turns out
6215 * that the lack of mic bias for this NID is intentional we could change the
6216 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6217 *
6218 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6219 * don't appear to make the mic bias available from the "line" jack, even
6220 * though the NID used for this jack (0x14) can supply it. The theory is
6221 * that perhaps Acer have included blocking capacitors between the ALC260
6222 * and the output jack. If this turns out to be the case for all such
6223 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6224 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006225 *
6226 * The C20x Tablet series have a mono internal speaker which is controlled
6227 * via the chip's Mono sum widget and pin complex, so include the necessary
6228 * controls for such models. On models without a "mono speaker" the control
6229 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006230 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006231static const struct snd_kcontrol_new alc260_acer_mixer[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006232 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6233 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006234 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006235 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006236 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006237 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006238 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006239 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6240 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6241 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6242 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6243 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6244 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6245 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6246 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006247 { } /* end */
6248};
6249
Michael Schwingencc959482009-02-22 18:58:45 +01006250/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6251 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006252static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006253 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6254 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6255 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6256 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6257 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6258 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6259 { } /* end */
6260};
6261
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006262/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6263 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6264 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006265static const struct snd_kcontrol_new alc260_will_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006266 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6267 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6268 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6269 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6270 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6271 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6272 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6273 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6274 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6275 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006276 { } /* end */
6277};
6278
6279/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6280 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6281 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006282static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006283 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6284 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6285 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6286 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6287 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6288 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6289 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6290 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6291 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6292 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6293 { } /* end */
6294};
6295
Kailang Yangdf694da2005-12-05 19:42:22 +01006296/*
6297 * initialization verbs
6298 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006299static const struct hda_verb alc260_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006301 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006303 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006305 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006307 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006309 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006311 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006313 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006315 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006317 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6318 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006319 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 /* set connection select to line in (default select for this ADC) */
6321 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006322 /* mute capture amp left and right */
6323 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6324 /* set connection select to line in (default select for this ADC) */
6325 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006326 /* set vol=0 Line-Out mixer amp left and right */
6327 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6328 /* unmute pin widget amp left and right (no gain on this amp) */
6329 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6330 /* set vol=0 HP mixer amp left and right */
6331 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6332 /* unmute pin widget amp left and right (no gain on this amp) */
6333 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6334 /* set vol=0 Mono mixer amp left and right */
6335 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6336 /* unmute pin widget amp left and right (no gain on this amp) */
6337 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6338 /* unmute LINE-2 out pin */
6339 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006340 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6341 * Line In 2 = 0x03
6342 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006343 /* mute analog inputs */
6344 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6345 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6346 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6347 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6348 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006350 /* mute Front out path */
6351 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6352 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6353 /* mute Headphone out path */
6354 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6355 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6356 /* mute Mono out path */
6357 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6358 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 { }
6360};
6361
Takashi Iwai474167d2006-05-17 17:17:43 +02006362#if 0 /* should be identical with alc260_init_verbs? */
Takashi Iwaia9111322011-05-02 11:30:18 +02006363static const struct hda_verb alc260_hp_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006364 /* Headphone and output */
6365 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6366 /* mono output */
6367 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6368 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6369 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6370 /* Mic2 (front panel) pin widget for input and vref at 80% */
6371 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6372 /* Line In pin widget for input */
6373 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6374 /* Line-2 pin widget for output */
6375 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6376 /* CD pin widget for input */
6377 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6378 /* unmute amp left and right */
6379 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6380 /* set connection select to line in (default select for this ADC) */
6381 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6382 /* unmute Line-Out mixer amp left and right (volume = 0) */
6383 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6384 /* mute pin widget amp left and right (no gain on this amp) */
6385 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6386 /* unmute HP mixer amp left and right (volume = 0) */
6387 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6388 /* mute pin widget amp left and right (no gain on this amp) */
6389 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006390 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6391 * Line In 2 = 0x03
6392 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006393 /* mute analog inputs */
6394 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6395 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6396 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6397 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6398 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006399 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6400 /* Unmute Front out path */
6401 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6402 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6403 /* Unmute Headphone out path */
6404 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6405 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6406 /* Unmute Mono out path */
6407 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6408 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6409 { }
6410};
Takashi Iwai474167d2006-05-17 17:17:43 +02006411#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006412
Takashi Iwaia9111322011-05-02 11:30:18 +02006413static const struct hda_verb alc260_hp_3013_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006414 /* Line out and output */
6415 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6416 /* mono output */
6417 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6418 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6419 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6420 /* Mic2 (front panel) pin widget for input and vref at 80% */
6421 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6422 /* Line In pin widget for input */
6423 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6424 /* Headphone pin widget for output */
6425 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6426 /* CD pin widget for input */
6427 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6428 /* unmute amp left and right */
6429 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6430 /* set connection select to line in (default select for this ADC) */
6431 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6432 /* unmute Line-Out mixer amp left and right (volume = 0) */
6433 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6434 /* mute pin widget amp left and right (no gain on this amp) */
6435 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6436 /* unmute HP mixer amp left and right (volume = 0) */
6437 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6438 /* mute pin widget amp left and right (no gain on this amp) */
6439 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006440 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6441 * Line In 2 = 0x03
6442 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006443 /* mute analog inputs */
6444 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6445 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6446 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6447 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6448 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006449 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6450 /* Unmute Front out path */
6451 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6452 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6453 /* Unmute Headphone out path */
6454 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6455 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6456 /* Unmute Mono out path */
6457 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6458 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6459 { }
6460};
6461
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006462/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006463 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6464 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006465 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006466static const struct hda_verb alc260_fujitsu_init_verbs[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006467 /* Disable all GPIOs */
6468 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6469 /* Internal speaker is connected to headphone pin */
6470 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6471 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6472 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006473 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6474 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6475 /* Ensure all other unused pins are disabled and muted. */
6476 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6477 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006478 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006479 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006480 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006481 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6482 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6483 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006484
Jonathan Woithef7ace402006-02-28 11:46:14 +01006485 /* Disable digital (SPDIF) pins */
6486 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6487 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006488
Kailang Yangea1fb292008-08-26 12:58:38 +02006489 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006490 * when acting as an output.
6491 */
6492 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6493
6494 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006495 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6496 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6497 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6498 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6499 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6500 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6501 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6502 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6503 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006504
Jonathan Woithef7ace402006-02-28 11:46:14 +01006505 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6506 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6507 /* Unmute Line1 pin widget output buffer since it starts as an output.
6508 * If the pin mode is changed by the user the pin mode control will
6509 * take care of enabling the pin's input/output buffers as needed.
6510 * Therefore there's no need to enable the input buffer at this
6511 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006512 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006513 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006514 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006515 * mixer ctrl)
6516 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006517 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006518
Jonathan Woithef7ace402006-02-28 11:46:14 +01006519 /* Mute capture amp left and right */
6520 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006521 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006522 * in (on mic1 pin)
6523 */
6524 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006525
Jonathan Woithef7ace402006-02-28 11:46:14 +01006526 /* Do the same for the second ADC: mute capture input amp and
6527 * set ADC connection to line in (on mic1 pin)
6528 */
6529 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6530 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006531
Jonathan Woithef7ace402006-02-28 11:46:14 +01006532 /* Mute all inputs to mixer widget (even unconnected ones) */
6533 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6534 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6535 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6536 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6537 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6538 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6539 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6540 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006541
6542 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006543};
6544
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006545/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6546 * similar laptops (adapted from Fujitsu init verbs).
6547 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006548static const struct hda_verb alc260_acer_init_verbs[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006549 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6550 * the headphone jack. Turn this on and rely on the standard mute
6551 * methods whenever the user wants to turn these outputs off.
6552 */
6553 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6554 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6555 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6556 /* Internal speaker/Headphone jack is connected to Line-out pin */
6557 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6558 /* Internal microphone/Mic jack is connected to Mic1 pin */
6559 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6560 /* Line In jack is connected to Line1 pin */
6561 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006562 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6563 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006564 /* Ensure all other unused pins are disabled and muted. */
6565 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6566 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006567 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6568 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6569 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6570 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6571 /* Disable digital (SPDIF) pins */
6572 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6573 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6574
Kailang Yangea1fb292008-08-26 12:58:38 +02006575 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006576 * bus when acting as outputs.
6577 */
6578 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6579 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6580
6581 /* Start with output sum widgets muted and their output gains at min */
6582 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6583 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6584 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6585 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6586 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6587 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6588 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6589 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6590 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6591
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006592 /* Unmute Line-out pin widget amp left and right
6593 * (no equiv mixer ctrl)
6594 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006595 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006596 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6597 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006598 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6599 * inputs. If the pin mode is changed by the user the pin mode control
6600 * will take care of enabling the pin's input/output buffers as needed.
6601 * Therefore there's no need to enable the input buffer at this
6602 * stage.
6603 */
6604 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6605 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6606
6607 /* Mute capture amp left and right */
6608 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6609 /* Set ADC connection select to match default mixer setting - mic
6610 * (on mic1 pin)
6611 */
6612 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6613
6614 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006615 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006616 */
6617 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006618 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006619
6620 /* Mute all inputs to mixer widget (even unconnected ones) */
6621 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6622 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6623 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6624 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6625 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6626 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6627 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6628 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6629
6630 { }
6631};
6632
Michael Schwingencc959482009-02-22 18:58:45 +01006633/* Initialisation sequence for Maxdata Favorit 100XS
6634 * (adapted from Acer init verbs).
6635 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006636static const struct hda_verb alc260_favorit100_init_verbs[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006637 /* GPIO 0 enables the output jack.
6638 * Turn this on and rely on the standard mute
6639 * methods whenever the user wants to turn these outputs off.
6640 */
6641 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6642 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6643 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6644 /* Line/Mic input jack is connected to Mic1 pin */
6645 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6646 /* Ensure all other unused pins are disabled and muted. */
6647 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6648 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6649 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6650 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6651 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6652 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6653 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6654 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6655 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6656 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6657 /* Disable digital (SPDIF) pins */
6658 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6659 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6660
6661 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6662 * bus when acting as outputs.
6663 */
6664 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6665 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6666
6667 /* Start with output sum widgets muted and their output gains at min */
6668 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6669 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6670 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6671 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6672 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6673 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6674 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6675 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6676 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6677
6678 /* Unmute Line-out pin widget amp left and right
6679 * (no equiv mixer ctrl)
6680 */
6681 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6682 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6683 * inputs. If the pin mode is changed by the user the pin mode control
6684 * will take care of enabling the pin's input/output buffers as needed.
6685 * Therefore there's no need to enable the input buffer at this
6686 * stage.
6687 */
6688 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6689
6690 /* Mute capture amp left and right */
6691 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6692 /* Set ADC connection select to match default mixer setting - mic
6693 * (on mic1 pin)
6694 */
6695 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6696
6697 /* Do similar with the second ADC: mute capture input amp and
6698 * set ADC connection to mic to match ALSA's default state.
6699 */
6700 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6701 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6702
6703 /* Mute all inputs to mixer widget (even unconnected ones) */
6704 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6705 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6706 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6707 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6708 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6709 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6710 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6711 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6712
6713 { }
6714};
6715
Takashi Iwaia9111322011-05-02 11:30:18 +02006716static const struct hda_verb alc260_will_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006717 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6718 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6719 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6720 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6721 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6722 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6723 {}
6724};
6725
Takashi Iwaia9111322011-05-02 11:30:18 +02006726static const struct hda_verb alc260_replacer_672v_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006727 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6728 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6729 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6730
6731 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6732 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6733 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6734
6735 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6736 {}
6737};
6738
6739/* toggle speaker-output according to the hp-jack state */
6740static void alc260_replacer_672v_automute(struct hda_codec *codec)
6741{
6742 unsigned int present;
6743
6744 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006745 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006746 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006747 snd_hda_codec_write_cache(codec, 0x01, 0,
6748 AC_VERB_SET_GPIO_DATA, 1);
6749 snd_hda_codec_write_cache(codec, 0x0f, 0,
6750 AC_VERB_SET_PIN_WIDGET_CONTROL,
6751 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006752 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006753 snd_hda_codec_write_cache(codec, 0x01, 0,
6754 AC_VERB_SET_GPIO_DATA, 0);
6755 snd_hda_codec_write_cache(codec, 0x0f, 0,
6756 AC_VERB_SET_PIN_WIDGET_CONTROL,
6757 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006758 }
6759}
6760
6761static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6762 unsigned int res)
6763{
6764 if ((res >> 26) == ALC880_HP_EVENT)
6765 alc260_replacer_672v_automute(codec);
6766}
6767
Takashi Iwaia9111322011-05-02 11:30:18 +02006768static const struct hda_verb alc260_hp_dc7600_verbs[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006769 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6770 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6771 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6772 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6773 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6774 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6775 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6776 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6777 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6778 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6779 {}
6780};
6781
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006782/* Test configuration for debugging, modelled after the ALC880 test
6783 * configuration.
6784 */
6785#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006786static const hda_nid_t alc260_test_dac_nids[1] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006787 0x02,
6788};
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006789static const hda_nid_t alc260_test_adc_nids[2] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006790 0x04, 0x05,
6791};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006792/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006793 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006794 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006795 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006796static const struct hda_input_mux alc260_test_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006797 {
6798 .num_items = 7,
6799 .items = {
6800 { "MIC1 pin", 0x0 },
6801 { "MIC2 pin", 0x1 },
6802 { "LINE1 pin", 0x2 },
6803 { "LINE2 pin", 0x3 },
6804 { "CD pin", 0x4 },
6805 { "LINE-OUT pin", 0x5 },
6806 { "HP-OUT pin", 0x6 },
6807 },
6808 },
6809 {
6810 .num_items = 8,
6811 .items = {
6812 { "MIC1 pin", 0x0 },
6813 { "MIC2 pin", 0x1 },
6814 { "LINE1 pin", 0x2 },
6815 { "LINE2 pin", 0x3 },
6816 { "CD pin", 0x4 },
6817 { "Mixer", 0x5 },
6818 { "LINE-OUT pin", 0x6 },
6819 { "HP-OUT pin", 0x7 },
6820 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006821 },
6822};
Takashi Iwaia9111322011-05-02 11:30:18 +02006823static const struct snd_kcontrol_new alc260_test_mixer[] = {
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006824 /* Output driver widgets */
6825 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6826 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6827 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6828 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6829 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6830 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6831
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006832 /* Modes for retasking pin widgets
6833 * Note: the ALC260 doesn't seem to act on requests to enable mic
6834 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6835 * mention this restriction. At this stage it's not clear whether
6836 * this behaviour is intentional or is a hardware bug in chip
6837 * revisions available at least up until early 2006. Therefore for
6838 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6839 * choices, but if it turns out that the lack of mic bias for these
6840 * NIDs is intentional we could change their modes from
6841 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6842 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006843 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6844 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6845 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6846 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6847 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6848 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6849
6850 /* Loopback mixer controls */
6851 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6852 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6853 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6854 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6855 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6856 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6857 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6858 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6859 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6860 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006861 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6862 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6863 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6864 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006865
6866 /* Controls for GPIO pins, assuming they are configured as outputs */
6867 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6868 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6869 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6870 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6871
Jonathan Woithe92621f12006-02-28 11:47:47 +01006872 /* Switches to allow the digital IO pins to be enabled. The datasheet
6873 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006874 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006875 */
6876 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6877 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6878
Jonathan Woithef8225f62008-01-08 12:16:54 +01006879 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6880 * this output to turn on an external amplifier.
6881 */
6882 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6883 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6884
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006885 { } /* end */
6886};
Takashi Iwaia9111322011-05-02 11:30:18 +02006887static const struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006888 /* Enable all GPIOs as outputs with an initial value of 0 */
6889 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6890 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6891 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6892
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006893 /* Enable retasking pins as output, initially without power amp */
6894 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6895 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6896 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6897 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6898 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6899 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6900
Jonathan Woithe92621f12006-02-28 11:47:47 +01006901 /* Disable digital (SPDIF) pins initially, but users can enable
6902 * them via a mixer switch. In the case of SPDIF-out, this initverb
6903 * payload also sets the generation to 0, output to be in "consumer"
6904 * PCM format, copyright asserted, no pre-emphasis and no validity
6905 * control.
6906 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006907 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6908 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6909
Kailang Yangea1fb292008-08-26 12:58:38 +02006910 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006911 * OUT1 sum bus when acting as an output.
6912 */
6913 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6914 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6915 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6916 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6917
6918 /* Start with output sum widgets muted and their output gains at min */
6919 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6920 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6921 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6922 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6923 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6924 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6925 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6926 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6927 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6928
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006929 /* Unmute retasking pin widget output buffers since the default
6930 * state appears to be output. As the pin mode is changed by the
6931 * user the pin mode control will take care of enabling the pin's
6932 * input/output buffers as needed.
6933 */
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006934 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6935 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6936 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6937 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6938 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6939 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6940 /* Also unmute the mono-out pin widget */
6941 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6942
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006943 /* Mute capture amp left and right */
6944 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006945 /* Set ADC connection select to match default mixer setting (mic1
6946 * pin)
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006947 */
6948 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6949
6950 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006951 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01006952 */
6953 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6954 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6955
6956 /* Mute all inputs to mixer widget (even unconnected ones) */
6957 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6958 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6959 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6960 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6961 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6962 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6963 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6964 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6965
6966 { }
6967};
6968#endif
6969
Takashi Iwai63300792008-01-24 15:31:36 +01006970#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6971#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006972
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006973#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6974#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6975
Kailang Yangdf694da2005-12-05 19:42:22 +01006976/*
6977 * for BIOS auto-configuration
6978 */
6979
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02006980/* convert from pin to volume-mixer widget */
6981static hda_nid_t alc260_pin_to_vol_mix(hda_nid_t nid)
6982{
6983 if (nid >= 0x0f && nid <= 0x11)
6984 return nid - 0x7;
6985 else if (nid >= 0x12 && nid <= 0x15)
6986 return 0x08;
6987 else
6988 return 0;
6989}
6990
Kailang Yangdf694da2005-12-05 19:42:22 +01006991static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006992 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006993{
6994 hda_nid_t nid_vol;
6995 unsigned long vol_val, sw_val;
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02006996 int chs, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01006997
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02006998 nid_vol = alc260_pin_to_vol_mix(nid);
6999 if (!nid_vol)
Kailang Yangdf694da2005-12-05 19:42:22 +01007000 return 0; /* N/A */
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007001 if (nid == 0x11)
7002 chs = 2;
7003 else
7004 chs = 3;
7005 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, chs, 0, HDA_OUTPUT);
7006 sw_val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
Kailang Yangea1fb292008-08-26 12:58:38 +02007007
Takashi Iwai863b4512008-10-21 17:01:47 +02007008 if (!(*vol_bits & (1 << nid_vol))) {
7009 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007010 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02007011 if (err < 0)
7012 return err;
7013 *vol_bits |= (1 << nid_vol);
7014 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007015 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007016 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007017 return err;
7018 return 1;
7019}
7020
7021/* add playback controls from the parsed DAC table */
7022static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
7023 const struct auto_pin_cfg *cfg)
7024{
7025 hda_nid_t nid;
7026 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02007027 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007028
7029 spec->multiout.num_dacs = 1;
7030 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +02007031 spec->private_dac_nids[0] = 0x02;
Kailang Yangdf694da2005-12-05 19:42:22 +01007032
7033 nid = cfg->line_out_pins[0];
7034 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02007035 const char *pfx;
Takashi Iwai2e925dd2011-06-24 11:27:22 +02007036 int index;
7037 pfx = alc_get_line_out_pfx(spec, 0, true, &index);
Takashi Iwai23112d62009-08-25 16:07:08 +02007038 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007039 if (err < 0)
7040 return err;
7041 }
7042
Takashi Iwai82bc9552006-03-21 11:24:42 +01007043 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007044 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007045 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007046 if (err < 0)
7047 return err;
7048 }
7049
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007050 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007051 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007052 err = alc260_add_playback_controls(spec, nid, "Headphone",
7053 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007054 if (err < 0)
7055 return err;
7056 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007057 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007058}
7059
7060/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007061static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01007062 const struct auto_pin_cfg *cfg)
7063{
Takashi Iwai05f5f472009-08-25 13:10:18 +02007064 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01007065}
7066
7067static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
7068 hda_nid_t nid, int pin_type,
7069 int sel_idx)
7070{
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007071 hda_nid_t mix;
7072
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007073 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007074 /* need the manual connection? */
7075 if (nid >= 0x12) {
7076 int idx = nid - 0x12;
7077 snd_hda_codec_write(codec, idx + 0x0b, 0,
7078 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01007079 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007080
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007081 mix = alc260_pin_to_vol_mix(nid);
7082 if (!mix)
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007083 return;
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007084 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007085 AMP_OUT_ZERO);
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007086 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7087 AMP_IN_UNMUTE(0));
7088 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7089 AMP_IN_UNMUTE(1));
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007090}
7091
Kailang Yangdf694da2005-12-05 19:42:22 +01007092static void alc260_auto_init_multi_out(struct hda_codec *codec)
7093{
7094 struct alc_spec *spec = codec->spec;
7095 hda_nid_t nid;
7096
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007097 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007098 if (nid) {
7099 int pin_type = get_pin_type(spec->autocfg.line_out_type);
7100 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
7101 }
Kailang Yangea1fb292008-08-26 12:58:38 +02007102
Takashi Iwai82bc9552006-03-21 11:24:42 +01007103 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007104 if (nid)
7105 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
7106
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007107 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007108 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007109 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007110}
Kailang Yangdf694da2005-12-05 19:42:22 +01007111
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007112#define alc260_auto_init_analog_input alc880_auto_init_analog_input
Takashi Iwai7f311a42010-04-09 17:32:23 +02007113#define alc260_auto_init_input_src alc880_auto_init_input_src
7114
Kailang Yangdf694da2005-12-05 19:42:22 +01007115static int alc260_parse_auto_config(struct hda_codec *codec)
7116{
7117 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007118 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007119 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +01007120
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007121 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7122 alc260_ignore);
7123 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007124 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007125 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7126 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007127 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007128 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007129 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007130 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007131 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007132 return err;
7133
7134 spec->multiout.max_channels = 2;
7135
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007136 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007137 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007138 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007139 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007140
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007141 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007142 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007143
Kailang Yang6227cdc2010-02-25 08:36:52 +01007144 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007145
Kailang Yangdf694da2005-12-05 19:42:22 +01007146 return 1;
7147}
7148
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007149/* additional initialization for auto-configuration model */
7150static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007151{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007152 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007153 alc260_auto_init_multi_out(codec);
7154 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02007155 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007156 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007157 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007158 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007159}
7160
Takashi Iwaicb53c622007-08-10 17:21:45 +02007161#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02007162static const struct hda_amp_list alc260_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02007163 { 0x07, HDA_INPUT, 0 },
7164 { 0x07, HDA_INPUT, 1 },
7165 { 0x07, HDA_INPUT, 2 },
7166 { 0x07, HDA_INPUT, 3 },
7167 { 0x07, HDA_INPUT, 4 },
7168 { } /* end */
7169};
7170#endif
7171
Kailang Yangdf694da2005-12-05 19:42:22 +01007172/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007173 * Pin config fixes
7174 */
7175enum {
7176 PINFIX_HP_DC5750,
7177};
7178
Takashi Iwaifc091762010-08-04 23:53:36 +02007179static const struct alc_fixup alc260_fixups[] = {
7180 [PINFIX_HP_DC5750] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007181 .type = ALC_FIXUP_PINS,
7182 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +02007183 { 0x11, 0x90130110 }, /* speaker */
7184 { }
7185 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007186 },
7187};
7188
Takashi Iwaia9111322011-05-02 11:30:18 +02007189static const struct snd_pci_quirk alc260_fixup_tbl[] = {
Takashi Iwaifc091762010-08-04 23:53:36 +02007190 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7191 {}
7192};
7193
7194/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007195 * ALC260 configurations
7196 */
Takashi Iwaiea734962011-01-17 11:29:34 +01007197static const char * const alc260_models[ALC260_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007198 [ALC260_BASIC] = "basic",
7199 [ALC260_HP] = "hp",
7200 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007201 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007202 [ALC260_FUJITSU_S702X] = "fujitsu",
7203 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007204 [ALC260_WILL] = "will",
7205 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007206 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007207#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007208 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007209#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007210 [ALC260_AUTO] = "auto",
7211};
7212
Takashi Iwaia9111322011-05-02 11:30:18 +02007213static const struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007214 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007215 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007216 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007217 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007218 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007219 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007220 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007221 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007222 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007223 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7224 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7225 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7226 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7227 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7228 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7229 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7230 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7231 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007232 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007233 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007234 {}
7235};
7236
Takashi Iwaia9111322011-05-02 11:30:18 +02007237static const struct alc_config_preset alc260_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007238 [ALC260_BASIC] = {
7239 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007240 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007241 .init_verbs = { alc260_init_verbs },
7242 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7243 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007244 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007245 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007246 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7247 .channel_mode = alc260_modes,
7248 .input_mux = &alc260_capture_source,
7249 },
7250 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007251 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007252 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007253 .init_verbs = { alc260_init_verbs,
7254 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007255 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7256 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007257 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7258 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007259 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7260 .channel_mode = alc260_modes,
7261 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007262 .unsol_event = alc_sku_unsol_event,
7263 .setup = alc260_hp_setup,
7264 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007265 },
Kailang Yang3f878302008-08-26 13:02:23 +02007266 [ALC260_HP_DC7600] = {
7267 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007268 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007269 .init_verbs = { alc260_init_verbs,
7270 alc260_hp_dc7600_verbs },
7271 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7272 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007273 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7274 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007275 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7276 .channel_mode = alc260_modes,
7277 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007278 .unsol_event = alc_sku_unsol_event,
7279 .setup = alc260_hp_3012_setup,
7280 .init_hook = alc_inithook,
Kailang Yang3f878302008-08-26 13:02:23 +02007281 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007282 [ALC260_HP_3013] = {
7283 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007284 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007285 .init_verbs = { alc260_hp_3013_init_verbs,
7286 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007287 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7288 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007289 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7290 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007291 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7292 .channel_mode = alc260_modes,
7293 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007294 .unsol_event = alc_sku_unsol_event,
7295 .setup = alc260_hp_3013_setup,
7296 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007297 },
7298 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007299 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007300 .init_verbs = { alc260_fujitsu_init_verbs },
7301 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7302 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007303 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7304 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007305 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7306 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007307 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7308 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007309 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007310 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007311 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007312 .init_verbs = { alc260_acer_init_verbs },
7313 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7314 .dac_nids = alc260_dac_nids,
7315 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7316 .adc_nids = alc260_dual_adc_nids,
7317 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7318 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007319 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7320 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007321 },
Michael Schwingencc959482009-02-22 18:58:45 +01007322 [ALC260_FAVORIT100] = {
7323 .mixers = { alc260_favorit100_mixer },
7324 .init_verbs = { alc260_favorit100_init_verbs },
7325 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7326 .dac_nids = alc260_dac_nids,
7327 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7328 .adc_nids = alc260_dual_adc_nids,
7329 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7330 .channel_mode = alc260_modes,
7331 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7332 .input_mux = alc260_favorit100_capture_sources,
7333 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007334 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007335 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007336 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7337 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7338 .dac_nids = alc260_dac_nids,
7339 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7340 .adc_nids = alc260_adc_nids,
7341 .dig_out_nid = ALC260_DIGOUT_NID,
7342 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7343 .channel_mode = alc260_modes,
7344 .input_mux = &alc260_capture_source,
7345 },
7346 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007347 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007348 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7349 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7350 .dac_nids = alc260_dac_nids,
7351 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7352 .adc_nids = alc260_adc_nids,
7353 .dig_out_nid = ALC260_DIGOUT_NID,
7354 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7355 .channel_mode = alc260_modes,
7356 .input_mux = &alc260_capture_source,
7357 .unsol_event = alc260_replacer_672v_unsol_event,
7358 .init_hook = alc260_replacer_672v_automute,
7359 },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007360#ifdef CONFIG_SND_DEBUG
7361 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007362 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007363 .init_verbs = { alc260_test_init_verbs },
7364 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7365 .dac_nids = alc260_test_dac_nids,
7366 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7367 .adc_nids = alc260_test_adc_nids,
7368 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7369 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007370 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7371 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e482006-02-09 12:01:26 +01007372 },
7373#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007374};
7375
Linus Torvalds1da177e2005-04-16 15:20:36 -07007376static int patch_alc260(struct hda_codec *codec)
7377{
7378 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007379 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007380
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007381 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007382 if (spec == NULL)
7383 return -ENOMEM;
7384
7385 codec->spec = spec;
7386
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007387 spec->mixer_nid = 0x07;
7388
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007389 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7390 alc260_models,
7391 alc260_cfg_tbl);
7392 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007393 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007394 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007395 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007396 }
7397
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007398 if (board_config == ALC260_AUTO) {
7399 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
7400 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7401 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007402
Kailang Yangdf694da2005-12-05 19:42:22 +01007403 if (board_config == ALC260_AUTO) {
7404 /* automatic parse from the BIOS config */
7405 err = alc260_parse_auto_config(codec);
7406 if (err < 0) {
7407 alc_free(codec);
7408 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007409 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007410 printk(KERN_INFO
7411 "hda_codec: Cannot set up configuration "
7412 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007413 board_config = ALC260_BASIC;
7414 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007416
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007417 err = snd_hda_attach_beep_device(codec, 0x1);
7418 if (err < 0) {
7419 alc_free(codec);
7420 return err;
7421 }
7422
Kailang Yangdf694da2005-12-05 19:42:22 +01007423 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007424 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007425
Linus Torvalds1da177e2005-04-16 15:20:36 -07007426 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7427 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307428 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007429
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007430 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7431 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7432
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007433 if (!spec->adc_nids && spec->input_mux) {
7434 /* check whether NID 0x04 is valid */
7435 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007436 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007437 /* get type */
7438 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7439 spec->adc_nids = alc260_adc_nids_alt;
7440 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7441 } else {
7442 spec->adc_nids = alc260_adc_nids;
7443 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7444 }
7445 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007446 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007447 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007448
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007449 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaifc091762010-08-04 23:53:36 +02007450
Takashi Iwai2134ea42008-01-10 16:53:55 +01007451 spec->vmaster_nid = 0x08;
7452
Linus Torvalds1da177e2005-04-16 15:20:36 -07007453 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007454 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007455 spec->init_hook = alc260_auto_init;
Takashi Iwai1c7161532011-04-07 10:37:16 +02007456 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007457#ifdef CONFIG_SND_HDA_POWER_SAVE
7458 if (!spec->loopback.amplist)
7459 spec->loopback.amplist = alc260_loopbacks;
7460#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007461
7462 return 0;
7463}
7464
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007465
Linus Torvalds1da177e2005-04-16 15:20:36 -07007466/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007467 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468 *
7469 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7470 * configuration. Each pin widget can choose any input DACs and a mixer.
7471 * Each ADC is connected from a mixer of all inputs. This makes possible
7472 * 6-channel independent captures.
7473 *
7474 * In addition, an independent DAC for the multi-playback (not used in this
7475 * driver yet).
7476 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007477#define ALC882_DIGOUT_NID 0x06
7478#define ALC882_DIGIN_NID 0x0a
Takashi Iwai4953550a2009-06-30 15:28:30 +02007479#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7480#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7481#define ALC1200_DIGOUT_NID 0x10
7482
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483
Takashi Iwaia9111322011-05-02 11:30:18 +02007484static const struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007485 { 8, NULL }
7486};
7487
Takashi Iwai4953550a2009-06-30 15:28:30 +02007488/* DACs */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007489static const hda_nid_t alc882_dac_nids[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007490 /* front, rear, clfe, rear_surr */
7491 0x02, 0x03, 0x04, 0x05
7492};
Takashi Iwai4953550a2009-06-30 15:28:30 +02007493#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007494
Takashi Iwai4953550a2009-06-30 15:28:30 +02007495/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007496#define alc882_adc_nids alc880_adc_nids
7497#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai4953550a2009-06-30 15:28:30 +02007498#define alc883_adc_nids alc882_adc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007499static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7500static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02007501#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007502
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007503static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7504static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02007505#define alc883_capsrc_nids alc882_capsrc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007506static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
Takashi Iwai4953550a2009-06-30 15:28:30 +02007507#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007508
Linus Torvalds1da177e2005-04-16 15:20:36 -07007509/* input MUX */
7510/* FIXME: should be a matrix-type input source selection */
7511
Takashi Iwaia9111322011-05-02 11:30:18 +02007512static const struct hda_input_mux alc882_capture_source = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007513 .num_items = 4,
7514 .items = {
7515 { "Mic", 0x0 },
7516 { "Front Mic", 0x1 },
7517 { "Line", 0x2 },
7518 { "CD", 0x4 },
7519 },
7520};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007521
Takashi Iwai4953550a2009-06-30 15:28:30 +02007522#define alc883_capture_source alc882_capture_source
7523
Takashi Iwaia9111322011-05-02 11:30:18 +02007524static const struct hda_input_mux alc889_capture_source = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007525 .num_items = 3,
7526 .items = {
7527 { "Front Mic", 0x0 },
7528 { "Mic", 0x3 },
7529 { "Line", 0x2 },
7530 },
7531};
7532
Takashi Iwaia9111322011-05-02 11:30:18 +02007533static const struct hda_input_mux mb5_capture_source = {
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007534 .num_items = 3,
7535 .items = {
7536 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307537 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007538 { "CD", 0x4 },
7539 },
7540};
7541
Takashi Iwaia9111322011-05-02 11:30:18 +02007542static const struct hda_input_mux macmini3_capture_source = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007543 .num_items = 2,
7544 .items = {
7545 { "Line", 0x2 },
7546 { "CD", 0x4 },
7547 },
7548};
7549
Takashi Iwaia9111322011-05-02 11:30:18 +02007550static const struct hda_input_mux alc883_3stack_6ch_intel = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007551 .num_items = 4,
7552 .items = {
7553 { "Mic", 0x1 },
7554 { "Front Mic", 0x0 },
7555 { "Line", 0x2 },
7556 { "CD", 0x4 },
7557 },
7558};
7559
Takashi Iwaia9111322011-05-02 11:30:18 +02007560static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007561 .num_items = 2,
7562 .items = {
7563 { "Mic", 0x1 },
7564 { "Line", 0x2 },
7565 },
7566};
7567
Takashi Iwaia9111322011-05-02 11:30:18 +02007568static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007569 .num_items = 4,
7570 .items = {
7571 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007572 { "Internal Mic", 0x1 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007573 { "Line", 0x2 },
7574 { "CD", 0x4 },
7575 },
7576};
7577
Takashi Iwaia9111322011-05-02 11:30:18 +02007578static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007579 .num_items = 2,
7580 .items = {
7581 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007582 { "Internal Mic", 0x1 },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007583 },
7584};
7585
Takashi Iwaia9111322011-05-02 11:30:18 +02007586static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007587 .num_items = 3,
7588 .items = {
7589 { "Mic", 0x0 },
7590 { "Front Mic", 0x1 },
7591 { "Line", 0x4 },
7592 },
7593};
7594
Takashi Iwaia9111322011-05-02 11:30:18 +02007595static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007596 .num_items = 2,
7597 .items = {
7598 { "Mic", 0x0 },
7599 { "Line", 0x2 },
7600 },
7601};
7602
Takashi Iwaia9111322011-05-02 11:30:18 +02007603static const struct hda_input_mux alc889A_mb31_capture_source = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007604 .num_items = 2,
7605 .items = {
7606 { "Mic", 0x0 },
7607 /* Front Mic (0x01) unused */
7608 { "Line", 0x2 },
7609 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007610 /* CD (0x04) unused? */
Takashi Iwai4953550a2009-06-30 15:28:30 +02007611 },
7612};
7613
Takashi Iwaia9111322011-05-02 11:30:18 +02007614static const struct hda_input_mux alc889A_imac91_capture_source = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007615 .num_items = 2,
7616 .items = {
7617 { "Mic", 0x01 },
7618 { "Line", 0x2 }, /* Not sure! */
7619 },
7620};
7621
Takashi Iwai4953550a2009-06-30 15:28:30 +02007622/*
7623 * 2ch mode
7624 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007625static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007626 { 2, NULL }
7627};
7628
Kailang Yangdf694da2005-12-05 19:42:22 +01007629/*
Kailang Yang272a5272007-05-14 11:00:38 +02007630 * 2ch mode
7631 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007632static const struct hda_verb alc882_3ST_ch2_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007633 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7634 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7635 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7636 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7637 { } /* end */
7638};
7639
7640/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007641 * 4ch mode
7642 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007643static const struct hda_verb alc882_3ST_ch4_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007644 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7645 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7646 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7647 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7648 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7649 { } /* end */
7650};
7651
7652/*
Kailang Yang272a5272007-05-14 11:00:38 +02007653 * 6ch mode
7654 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007655static const struct hda_verb alc882_3ST_ch6_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007656 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7657 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7658 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7659 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7660 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7661 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7662 { } /* end */
7663};
7664
Takashi Iwaia9111322011-05-02 11:30:18 +02007665static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007666 { 2, alc882_3ST_ch2_init },
Takashi Iwai4953550a2009-06-30 15:28:30 +02007667 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007668 { 6, alc882_3ST_ch6_init },
7669};
7670
Takashi Iwai4953550a2009-06-30 15:28:30 +02007671#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7672
Kailang Yang272a5272007-05-14 11:00:38 +02007673/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307674 * 2ch mode
7675 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007676static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307677 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7678 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7679 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7680 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7681 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7682 { } /* end */
7683};
7684
7685/*
7686 * 4ch mode
7687 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007688static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307689 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7690 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7691 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7692 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7693 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7694 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7695 { } /* end */
7696};
7697
7698/*
7699 * 6ch mode
7700 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007701static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307702 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7703 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7704 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7705 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7706 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7707 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7708 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7709 { } /* end */
7710};
7711
Takashi Iwaia9111322011-05-02 11:30:18 +02007712static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307713 { 2, alc883_3ST_ch2_clevo_init },
7714 { 4, alc883_3ST_ch4_clevo_init },
7715 { 6, alc883_3ST_ch6_clevo_init },
7716};
7717
7718
7719/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007720 * 6ch mode
7721 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007722static const struct hda_verb alc882_sixstack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007723 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7724 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7725 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7726 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7727 { } /* end */
7728};
7729
7730/*
7731 * 8ch mode
7732 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007733static const struct hda_verb alc882_sixstack_ch8_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007734 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7735 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7736 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7737 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7738 { } /* end */
7739};
7740
Takashi Iwaia9111322011-05-02 11:30:18 +02007741static const struct hda_channel_mode alc882_sixstack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007742 { 6, alc882_sixstack_ch6_init },
7743 { 8, alc882_sixstack_ch8_init },
7744};
7745
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007746
7747/* Macbook Air 2,1 */
7748
Takashi Iwaia9111322011-05-02 11:30:18 +02007749static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007750 { 2, NULL },
7751};
7752
Takashi Iwai87350ad2007-08-16 18:19:38 +02007753/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007754 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007755 */
7756
7757/*
7758 * 2ch mode
7759 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007760static const struct hda_verb alc885_mbp_ch2_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007761 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7762 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7763 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7764 { } /* end */
7765};
7766
7767/*
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007768 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007769 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007770static const struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007771 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7772 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7773 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7774 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7775 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7776 { } /* end */
7777};
7778
Takashi Iwaia9111322011-05-02 11:30:18 +02007779static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007780 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730af2009-08-31 08:15:26 +02007781 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007782};
7783
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007784/*
7785 * 2ch
7786 * Speakers/Woofer/HP = Front
7787 * LineIn = Input
7788 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007789static const struct hda_verb alc885_mb5_ch2_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007790 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7791 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7792 { } /* end */
7793};
7794
7795/*
7796 * 6ch mode
7797 * Speakers/HP = Front
7798 * Woofer = LFE
7799 * LineIn = Surround
7800 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007801static const struct hda_verb alc885_mb5_ch6_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007802 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7803 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7804 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7805 { } /* end */
7806};
7807
Takashi Iwaia9111322011-05-02 11:30:18 +02007808static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007809 { 2, alc885_mb5_ch2_init },
7810 { 6, alc885_mb5_ch6_init },
7811};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007812
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007813#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai4953550a2009-06-30 15:28:30 +02007814
7815/*
7816 * 2ch mode
7817 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007818static const struct hda_verb alc883_4ST_ch2_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007819 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7820 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7821 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7822 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7823 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7824 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7825 { } /* end */
7826};
7827
7828/*
7829 * 4ch mode
7830 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007831static const struct hda_verb alc883_4ST_ch4_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007832 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7833 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7834 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7835 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7836 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7837 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7838 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7839 { } /* end */
7840};
7841
7842/*
7843 * 6ch mode
7844 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007845static const struct hda_verb alc883_4ST_ch6_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007846 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7847 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7848 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7849 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7850 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7851 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7852 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7853 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7854 { } /* end */
7855};
7856
7857/*
7858 * 8ch mode
7859 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007860static const struct hda_verb alc883_4ST_ch8_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007861 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7862 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7863 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7864 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7865 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7866 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7867 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7868 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7869 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7870 { } /* end */
7871};
7872
Takashi Iwaia9111322011-05-02 11:30:18 +02007873static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007874 { 2, alc883_4ST_ch2_init },
7875 { 4, alc883_4ST_ch4_init },
7876 { 6, alc883_4ST_ch6_init },
7877 { 8, alc883_4ST_ch8_init },
7878};
7879
7880
7881/*
7882 * 2ch mode
7883 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007884static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007885 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7886 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7887 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7888 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7889 { } /* end */
7890};
7891
7892/*
7893 * 4ch mode
7894 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007895static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007896 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7897 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7898 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7899 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7900 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7901 { } /* end */
7902};
7903
7904/*
7905 * 6ch mode
7906 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007907static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007908 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7909 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7910 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7911 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7912 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7913 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7914 { } /* end */
7915};
7916
Takashi Iwaia9111322011-05-02 11:30:18 +02007917static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007918 { 2, alc883_3ST_ch2_intel_init },
7919 { 4, alc883_3ST_ch4_intel_init },
7920 { 6, alc883_3ST_ch6_intel_init },
7921};
7922
7923/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007924 * 2ch mode
7925 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007926static const struct hda_verb alc889_ch2_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007927 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7928 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7929 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7930 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7931 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7932 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7933 { } /* end */
7934};
7935
7936/*
Takashi Iwai4953550a2009-06-30 15:28:30 +02007937 * 6ch mode
7938 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007939static const struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007940 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7941 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7942 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7943 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7944 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007945 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7946 { } /* end */
7947};
7948
7949/*
7950 * 8ch mode
7951 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007952static const struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007953 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7954 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7955 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7956 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7957 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007958 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7959 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007960 { } /* end */
7961};
7962
Takashi Iwaia9111322011-05-02 11:30:18 +02007963static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007964 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007965 { 6, alc889_ch6_intel_init },
7966 { 8, alc889_ch8_intel_init },
7967};
7968
7969/*
7970 * 6ch mode
7971 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007972static const struct hda_verb alc883_sixstack_ch6_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007973 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7974 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7975 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7976 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7977 { } /* end */
7978};
7979
7980/*
7981 * 8ch mode
7982 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007983static const struct hda_verb alc883_sixstack_ch8_init[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007984 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7985 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7986 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7987 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7988 { } /* end */
7989};
7990
Takashi Iwaia9111322011-05-02 11:30:18 +02007991static const struct hda_channel_mode alc883_sixstack_modes[2] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02007992 { 6, alc883_sixstack_ch6_init },
7993 { 8, alc883_sixstack_ch8_init },
7994};
7995
7996
Linus Torvalds1da177e2005-04-16 15:20:36 -07007997/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7998 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7999 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008000static const struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02008001 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008002 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008003 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008004 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008005 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8006 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008007 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8008 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008009 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008010 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008011 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8012 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8013 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8014 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8015 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8016 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008017 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008018 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8019 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008020 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008021 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008022 { } /* end */
8023};
8024
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008025/* Macbook Air 2,1 same control for HP and internal Speaker */
8026
Takashi Iwaia9111322011-05-02 11:30:18 +02008027static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008028 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8029 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
8030 { }
8031};
8032
8033
Takashi Iwaia9111322011-05-02 11:30:18 +02008034static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008035 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8036 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
8037 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8038 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
8039 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01008040 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8041 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008042 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8043 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008044 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
8045 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008046 { } /* end */
8047};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008048
Takashi Iwaia9111322011-05-02 11:30:18 +02008049static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008050 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8051 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8052 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8053 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8054 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8055 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10308056 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8057 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09308058 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8059 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008060 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8061 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008062 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
8063 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008064 { } /* end */
8065};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008066
Takashi Iwaia9111322011-05-02 11:30:18 +02008067static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008068 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8069 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8070 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8071 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8072 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8073 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
8074 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8075 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
8076 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8077 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008078 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008079 { } /* end */
8080};
8081
Takashi Iwaia9111322011-05-02 11:30:18 +02008082static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008083 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8084 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008085 { } /* end */
8086};
8087
8088
Takashi Iwaia9111322011-05-02 11:30:18 +02008089static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02008090 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8091 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8092 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8093 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8094 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8095 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008097 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008098 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008099 { } /* end */
8100};
8101
Takashi Iwaia9111322011-05-02 11:30:18 +02008102static const struct snd_kcontrol_new alc882_targa_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008103 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8104 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8105 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8106 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8107 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8108 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8109 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8110 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8111 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008112 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008113 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8114 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008115 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008116 { } /* end */
8117};
8118
8119/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8120 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8121 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008122static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008123 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8124 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8125 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8126 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8127 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8128 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8129 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8130 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8131 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8132 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8133 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8134 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008135 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008136 { } /* end */
8137};
8138
Takashi Iwaia9111322011-05-02 11:30:18 +02008139static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008140 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8141 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8142 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8143 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8144 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8145 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8146 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8147 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008148 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008149 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008150 { } /* end */
8151};
8152
Takashi Iwaia9111322011-05-02 11:30:18 +02008153static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008154 {
8155 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8156 .name = "Channel Mode",
8157 .info = alc_ch_mode_info,
8158 .get = alc_ch_mode_get,
8159 .put = alc_ch_mode_put,
8160 },
8161 { } /* end */
8162};
8163
Takashi Iwaia9111322011-05-02 11:30:18 +02008164static const struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008165 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008166 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8167 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008168 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008169 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8170 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008172 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8173 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008174 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008175 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8176 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008177
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008178 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008179 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008180 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008181 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008182 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008183 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008184 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008185 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008186 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008187 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008188 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008189 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008190 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008191 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008192 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008193 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008194 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008195 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008196 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8197 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008198 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8200 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008201 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008202 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8203 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8204 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8205 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8206 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008207 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008208 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008209
8210 /* FIXME: use matrix-type input source selection */
8211 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008212 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008213 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008214 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008215 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008216 /* ADC2: mute amp left and right */
8217 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008218 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008219 /* ADC3: mute amp left and right */
8220 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008221 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008222
8223 { }
8224};
8225
Takashi Iwaia9111322011-05-02 11:30:18 +02008226static const struct hda_verb alc882_adc1_init_verbs[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02008227 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8228 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8229 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8230 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8231 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8232 /* ADC1: mute amp left and right */
8233 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8234 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8235 { }
8236};
8237
Takashi Iwaia9111322011-05-02 11:30:18 +02008238static const struct hda_verb alc882_eapd_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008239 /* change to EAPD mode */
8240 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008241 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008242 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008243};
8244
Takashi Iwaia9111322011-05-02 11:30:18 +02008245static const struct hda_verb alc889_eapd_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008246 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8247 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8248 { }
8249};
8250
Takashi Iwaia9111322011-05-02 11:30:18 +02008251static const struct hda_verb alc_hp15_unsol_verbs[] = {
Wu Fengguang6732bd02009-07-30 09:19:14 +02008252 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8253 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8254 {}
8255};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008256
Takashi Iwaia9111322011-05-02 11:30:18 +02008257static const struct hda_verb alc885_init_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008258 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008259 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8260 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008261 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008262 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8263 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008264 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008265 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8266 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008267 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008268 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8269 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008270
8271 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008272 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008273 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8274 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8275 /* Front Pin: output 0 (0x0c) */
8276 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8277 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8278 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8279 /* Rear Pin: output 1 (0x0d) */
8280 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8281 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8282 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8283 /* CLFE Pin: output 2 (0x0e) */
8284 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8285 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8286 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8287 /* Side Pin: output 3 (0x0f) */
8288 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8289 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8290 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8291 /* Mic (rear) pin: input vref at 80% */
8292 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8293 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8294 /* Front Mic pin: input vref at 80% */
8295 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8296 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8297 /* Line In pin: input */
8298 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8299 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8300
8301 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8302 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008303 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008304 /* Input mixer2 */
8305 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008306 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008307 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008308 /* ADC2: mute amp left and right */
8309 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8310 /* ADC3: mute amp left and right */
8311 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8312
8313 { }
8314};
8315
Takashi Iwaia9111322011-05-02 11:30:18 +02008316static const struct hda_verb alc885_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008317 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8318 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8319 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8320 { }
8321};
8322
8323
8324/* Unmute Selector 24h and set the default input to front mic */
Takashi Iwaia9111322011-05-02 11:30:18 +02008325static const struct hda_verb alc889_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008326 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8327 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8328 { }
8329};
8330
8331
Takashi Iwai4953550a2009-06-30 15:28:30 +02008332#define alc883_init_verbs alc882_base_init_verbs
8333
Tobin Davis9102cd12006-12-15 10:02:12 +01008334/* Mac Pro test */
Takashi Iwaia9111322011-05-02 11:30:18 +02008335static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008336 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8337 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8338 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8339 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8340 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008341 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008342 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8343 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008344 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008345 { } /* end */
8346};
8347
Takashi Iwaia9111322011-05-02 11:30:18 +02008348static const struct hda_verb alc882_macpro_init_verbs[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008349 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8350 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8351 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8352 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8353 /* Front Pin: output 0 (0x0c) */
8354 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8355 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8356 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8357 /* Front Mic pin: input vref at 80% */
8358 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8359 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8360 /* Speaker: output */
8361 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8362 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8363 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8364 /* Headphone output (output 0 - 0x0c) */
8365 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8366 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8367 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8368
8369 /* FIXME: use matrix-type input source selection */
8370 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8371 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8372 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8373 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8374 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8376 /* Input mixer2 */
8377 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8378 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8379 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8380 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8381 /* Input mixer3 */
8382 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8383 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8384 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8385 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8386 /* ADC1: mute amp left and right */
8387 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8388 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8389 /* ADC2: mute amp left and right */
8390 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8391 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8392 /* ADC3: mute amp left and right */
8393 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8394 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8395
8396 { }
8397};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008398
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008399/* Macbook 5,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008400static const struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008401 /* DACs */
8402 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8403 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8404 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8405 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008406 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008407 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8408 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8409 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008410 /* Surround mixer */
8411 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8412 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8413 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8414 /* LFE mixer */
8415 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8416 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8417 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8418 /* HP mixer */
8419 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8420 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8421 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8422 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008423 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8424 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008425 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8426 /* LFE Pin (0x0e) */
8427 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8428 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8429 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8430 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008431 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8432 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008433 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308434 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008435 /* Front Mic pin: input vref at 80% */
8436 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8437 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8438 /* Line In pin */
8439 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8440 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8441
Alex Murrayb8f171e2010-06-14 12:08:43 +09308442 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8443 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8444 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008445 { }
8446};
8447
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008448/* Macmini 3,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008449static const struct hda_verb alc885_macmini3_init_verbs[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008450 /* DACs */
8451 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8452 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8453 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8454 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8455 /* Front mixer */
8456 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8457 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8458 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8459 /* Surround mixer */
8460 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8461 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8462 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8463 /* LFE mixer */
8464 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8465 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8466 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8467 /* HP mixer */
8468 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8469 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8470 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8471 /* Front Pin (0x0c) */
8472 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8473 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8474 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8475 /* LFE Pin (0x0e) */
8476 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8477 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8478 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8479 /* HP Pin (0x0f) */
8480 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8481 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8482 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8483 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8484 /* Line In pin */
8485 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8486 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8487
8488 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8489 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8490 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8491 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8492 { }
8493};
8494
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008495
Takashi Iwaia9111322011-05-02 11:30:18 +02008496static const struct hda_verb alc885_mba21_init_verbs[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008497 /*Internal and HP Speaker Mixer*/
8498 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8499 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8500 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8501 /*Internal Speaker Pin (0x0c)*/
8502 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8503 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8504 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8505 /* HP Pin: output 0 (0x0e) */
8506 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8507 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8508 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8509 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8510 /* Line in (is hp when jack connected)*/
8511 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8512 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8513
8514 { }
8515 };
8516
8517
Takashi Iwai87350ad2007-08-16 18:19:38 +02008518/* Macbook Pro rev3 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008519static const struct hda_verb alc885_mbp3_init_verbs[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02008520 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8521 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8522 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8523 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8524 /* Rear mixer */
8525 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8526 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8527 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008528 /* HP mixer */
8529 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8530 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8531 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008532 /* Front Pin: output 0 (0x0c) */
8533 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8534 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8535 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008536 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008537 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730af2009-08-31 08:15:26 +02008538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8539 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008540 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8541 /* Mic (rear) pin: input vref at 80% */
8542 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8543 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8544 /* Front Mic pin: input vref at 80% */
8545 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8546 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8547 /* Line In pin: use output 1 when in LineOut mode */
8548 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8549 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8550 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8551
8552 /* FIXME: use matrix-type input source selection */
8553 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8554 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8555 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8556 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8557 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8558 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8559 /* Input mixer2 */
8560 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8561 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8562 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8563 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8564 /* Input mixer3 */
8565 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8566 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8567 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8568 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8569 /* ADC1: mute amp left and right */
8570 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8571 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8572 /* ADC2: mute amp left and right */
8573 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8574 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8575 /* ADC3: mute amp left and right */
8576 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8577 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8578
8579 { }
8580};
8581
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008582/* iMac 9,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008583static const struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008584 /* Internal Speaker Pin (0x0c) */
8585 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8586 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8587 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8588 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8589 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8590 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8591 /* HP Pin: Rear */
8592 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8593 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8594 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8595 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8596 /* Line in Rear */
8597 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8598 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8599 /* Front Mic pin: input vref at 80% */
8600 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8601 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008602 /* Rear mixer */
8603 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8604 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8605 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008606 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8607 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8608 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8609 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8610 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008611 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8612 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8613 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8614 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008615 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008616 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8617 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8618 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8619 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008620 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8622 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8623 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8624 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008625 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008626 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8627 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008628 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008629 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8630 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008631 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008632 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8633 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008634 { }
8635};
8636
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008637/* iMac 24 mixer. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008638static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008639 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8640 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8641 { } /* end */
8642};
8643
8644/* iMac 24 init verbs. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008645static const struct hda_verb alc885_imac24_init_verbs[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008646 /* Internal speakers: output 0 (0x0c) */
8647 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8648 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8649 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8650 /* Internal speakers: output 0 (0x0c) */
8651 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8652 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8653 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8654 /* Headphone: output 0 (0x0c) */
8655 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8656 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8657 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8658 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8659 /* Front Mic: input vref at 80% */
8660 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8661 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8662 { }
8663};
8664
8665/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008666static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008667{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008668 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008669
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008670 spec->autocfg.hp_pins[0] = 0x14;
8671 spec->autocfg.speaker_pins[0] = 0x18;
8672 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008673 spec->automute = 1;
8674 spec->automute_mode = ALC_AUTOMUTE_AMP;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008675}
8676
Takashi Iwai9d54f082010-02-22 08:34:40 +01008677#define alc885_mb5_setup alc885_imac24_setup
8678#define alc885_macmini3_setup alc885_imac24_setup
8679
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008680/* Macbook Air 2,1 */
8681static void alc885_mba21_setup(struct hda_codec *codec)
8682{
8683 struct alc_spec *spec = codec->spec;
8684
8685 spec->autocfg.hp_pins[0] = 0x14;
8686 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02008687 spec->automute = 1;
8688 spec->automute_mode = ALC_AUTOMUTE_AMP;
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008689}
8690
8691
8692
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008693static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008694{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008695 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008696
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008697 spec->autocfg.hp_pins[0] = 0x15;
8698 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02008699 spec->automute = 1;
8700 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008701}
8702
Takashi Iwai9d54f082010-02-22 08:34:40 +01008703static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308704{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008705 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308706
Takashi Iwai9d54f082010-02-22 08:34:40 +01008707 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008708 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008709 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008710 spec->automute = 1;
8711 spec->automute_mode = ALC_AUTOMUTE_AMP;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008712}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008713
Takashi Iwaia9111322011-05-02 11:30:18 +02008714static const struct hda_verb alc882_targa_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008715 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8716 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8717
8718 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8719 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008720
Kailang Yang272a5272007-05-14 11:00:38 +02008721 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8722 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8723 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8724
8725 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008726 { } /* end */
8727};
8728
8729/* toggle speaker-output according to the hp-jack state */
8730static void alc882_targa_automute(struct hda_codec *codec)
8731{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008732 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02008733 alc_hp_automute(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008734 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008735 spec->jack_present ? 1 : 3);
8736}
8737
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008738static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008739{
8740 struct alc_spec *spec = codec->spec;
8741
8742 spec->autocfg.hp_pins[0] = 0x14;
8743 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02008744 spec->automute = 1;
8745 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02008746}
8747
8748static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8749{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008750 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008751 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008752}
8753
Takashi Iwaia9111322011-05-02 11:30:18 +02008754static const struct hda_verb alc882_asus_a7j_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008755 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8756 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8757
8758 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8759 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8760 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008761
Kailang Yang272a5272007-05-14 11:00:38 +02008762 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8763 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8764 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8765
8766 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8767 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8768 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8769 { } /* end */
8770};
8771
Takashi Iwaia9111322011-05-02 11:30:18 +02008772static const struct hda_verb alc882_asus_a7m_verbs[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008773 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8774 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8775
8776 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8777 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8778 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008779
Takashi Iwai914759b2007-09-06 14:52:04 +02008780 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8781 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8782 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8783
8784 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8785 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8786 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8787 { } /* end */
8788};
8789
Tobin Davis9102cd12006-12-15 10:02:12 +01008790static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8791{
8792 unsigned int gpiostate, gpiomask, gpiodir;
8793
8794 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8795 AC_VERB_GET_GPIO_DATA, 0);
8796
8797 if (!muted)
8798 gpiostate |= (1 << pin);
8799 else
8800 gpiostate &= ~(1 << pin);
8801
8802 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8803 AC_VERB_GET_GPIO_MASK, 0);
8804 gpiomask |= (1 << pin);
8805
8806 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8807 AC_VERB_GET_GPIO_DIRECTION, 0);
8808 gpiodir |= (1 << pin);
8809
8810
8811 snd_hda_codec_write(codec, codec->afg, 0,
8812 AC_VERB_SET_GPIO_MASK, gpiomask);
8813 snd_hda_codec_write(codec, codec->afg, 0,
8814 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8815
8816 msleep(1);
8817
8818 snd_hda_codec_write(codec, codec->afg, 0,
8819 AC_VERB_SET_GPIO_DATA, gpiostate);
8820}
8821
Takashi Iwai7debbe52007-08-16 15:01:03 +02008822/* set up GPIO at initialization */
8823static void alc885_macpro_init_hook(struct hda_codec *codec)
8824{
8825 alc882_gpio_mute(codec, 0, 0);
8826 alc882_gpio_mute(codec, 1, 0);
8827}
8828
8829/* set up GPIO and update auto-muting at initialization */
8830static void alc885_imac24_init_hook(struct hda_codec *codec)
8831{
8832 alc885_macpro_init_hook(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02008833 alc_hp_automute(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008834}
8835
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008836/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008837static const struct hda_verb alc889A_mb31_ch2_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008838 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8839 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8840 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8841 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8842 { } /* end */
8843};
8844
8845/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008846static const struct hda_verb alc889A_mb31_ch4_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_OUT}, /* Line as output */
8850 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8851 { } /* end */
8852};
8853
8854/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008855static const struct hda_verb alc889A_mb31_ch5_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008856 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8857 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8858 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8859 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8860 { } /* end */
8861};
8862
8863/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008864static const struct hda_verb alc889A_mb31_ch6_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008865 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8866 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8867 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8868 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8869 { } /* end */
8870};
8871
Takashi Iwaia9111322011-05-02 11:30:18 +02008872static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008873 { 2, alc889A_mb31_ch2_init },
8874 { 4, alc889A_mb31_ch4_init },
8875 { 5, alc889A_mb31_ch5_init },
8876 { 6, alc889A_mb31_ch6_init },
8877};
8878
Takashi Iwaia9111322011-05-02 11:30:18 +02008879static const struct hda_verb alc883_medion_eapd_verbs[] = {
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008880 /* eanable EAPD on medion laptop */
8881 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8882 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8883 { }
8884};
8885
Takashi Iwai4953550a2009-06-30 15:28:30 +02008886#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008887
Takashi Iwaia9111322011-05-02 11:30:18 +02008888static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008889 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8890 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8891 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8892 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8893 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8894 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8895 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8896 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008897 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008898 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8899 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008900 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008901 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008902 { } /* end */
8903};
8904
Takashi Iwaia9111322011-05-02 11:30:18 +02008905static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008906 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8907 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8908 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8909 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8910 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008911 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008912 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008913 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008914 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008915 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008916 { } /* end */
8917};
8918
Takashi Iwaia9111322011-05-02 11:30:18 +02008919static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01008920 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8921 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8922 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8923 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8924 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008925 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008926 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008927 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008928 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008929 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008930 { } /* end */
8931};
8932
Takashi Iwaia9111322011-05-02 11:30:18 +02008933static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008934 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8935 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8936 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8937 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8938 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8939 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8940 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8941 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008942 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008943 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8944 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008945 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008946 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008947 { } /* end */
8948};
8949
Takashi Iwaia9111322011-05-02 11:30:18 +02008950static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008951 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8952 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8953 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8954 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8955 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8956 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8957 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8958 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8959 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8960 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8961 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8962 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8963 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8964 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008965 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008966 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8967 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008968 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008969 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008970 { } /* end */
8971};
8972
Takashi Iwaia9111322011-05-02 11:30:18 +02008973static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
Jiang zhe17bba1b2008-06-04 12:11:07 +02008974 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8975 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8976 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8977 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8978 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8979 HDA_OUTPUT),
8980 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8981 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8982 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8983 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8984 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8985 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8986 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8987 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8988 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008989 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008990 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8991 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008992 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008993 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008994 { } /* end */
8995};
8996
Takashi Iwaia9111322011-05-02 11:30:18 +02008997static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008998 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8999 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9000 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9001 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9002 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9003 HDA_OUTPUT),
9004 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9005 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9006 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9007 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9008 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
9009 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9010 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9011 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9012 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009013 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009014 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
9015 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009016 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009017 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9018 { } /* end */
9019};
9020
Takashi Iwaia9111322011-05-02 11:30:18 +02009021static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02009022 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009023 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009024 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009025 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009026 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9027 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009028 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9029 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009030 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9031 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9032 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9033 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9034 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9035 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009036 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009037 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9038 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009039 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009040 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009041 { } /* end */
9042};
9043
Takashi Iwaia9111322011-05-02 11:30:18 +02009044static const struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009045 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009046 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009047 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009048 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009049 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9050 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9051 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9052 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9053 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9054 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9055 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9056 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9057 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9058 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9059 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009060 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009061 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009062 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009063};
Kailang Yangccc656c2006-10-17 12:32:26 +02009064
Takashi Iwaia9111322011-05-02 11:30:18 +02009065static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009066 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009067 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009068 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009069 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009070 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9071 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9072 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009073 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009074 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009075 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009076 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009077 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009078 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009079};
Kailang Yangccc656c2006-10-17 12:32:26 +02009080
Takashi Iwaia9111322011-05-02 11:30:18 +02009081static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009082 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9083 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, 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),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009087 { } /* end */
9088};
9089
Takashi Iwaia9111322011-05-02 11:30:18 +02009090static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009091 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9092 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009093 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9094 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009095 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9096 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009097 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009098 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009099 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009100};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009101
Takashi Iwaia9111322011-05-02 11:30:18 +02009102static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009103 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9104 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9105 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9106 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9107 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9108 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9109 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009110 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9111 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009112 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02009113};
Kailang Yang272a5272007-05-14 11:00:38 +02009114
Takashi Iwaia9111322011-05-02 11:30:18 +02009115static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009116 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9117 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9118 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9119 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9120 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9121 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9122 { } /* end */
9123};
9124
Takashi Iwaia9111322011-05-02 11:30:18 +02009125static const struct hda_verb alc883_medion_wim2160_verbs[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009126 /* Unmute front mixer */
9127 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9128 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9129
9130 /* Set speaker pin to front mixer */
9131 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9132
9133 /* Init headphone pin */
9134 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9135 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9136 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9137 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9138
9139 { } /* end */
9140};
9141
9142/* toggle speaker-output according to the hp-jack state */
9143static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9144{
9145 struct alc_spec *spec = codec->spec;
9146
9147 spec->autocfg.hp_pins[0] = 0x1a;
9148 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009149 spec->automute = 1;
9150 spec->automute_mode = ALC_AUTOMUTE_AMP;
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009151}
9152
Takashi Iwaia9111322011-05-02 11:30:18 +02009153static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009154 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9155 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009156 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009157 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9158 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009159 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009160 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009161 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009162 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009163};
Tobin Davis2880a862007-08-07 11:50:26 +02009164
Takashi Iwaia9111322011-05-02 11:30:18 +02009165static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01009166 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009167 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009168 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9169 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009170 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9171 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9172 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009173 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009174 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9175 { } /* end */
9176};
9177
Takashi Iwaia9111322011-05-02 11:30:18 +02009178static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009179 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9180 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9181 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9182 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9183 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9184 0x0d, 1, 0x0, HDA_OUTPUT),
9185 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9186 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9187 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9188 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9189 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009190 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9191 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9192 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9193 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9194 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009195 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009196 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9197 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009198 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009199 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009200 { } /* end */
9201};
9202
Takashi Iwaia9111322011-05-02 11:30:18 +02009203static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009204 /* Output mixers */
9205 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9206 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9207 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9208 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9209 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9210 HDA_OUTPUT),
9211 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9212 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9213 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9214 /* Output switches */
9215 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9216 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9217 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9218 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009219 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9220 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009221 /* Input mixers */
9222 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9223 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9224 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9225 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9226 { } /* end */
9227};
9228
Takashi Iwaia9111322011-05-02 11:30:18 +02009229static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
Guido Günther3e1647c52009-06-05 00:47:26 +02009230 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9231 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9232 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9233 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009234 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c52009-06-05 00:47:26 +02009235 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9236 { } /* end */
9237};
9238
Takashi Iwaia9111322011-05-02 11:30:18 +02009239static const struct hda_bind_ctls alc883_bind_cap_vol = {
Kailang Yange2757d52008-08-26 13:17:46 +02009240 .ops = &snd_hda_bind_vol,
9241 .values = {
9242 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9243 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9244 0
9245 },
9246};
9247
Takashi Iwaia9111322011-05-02 11:30:18 +02009248static const struct hda_bind_ctls alc883_bind_cap_switch = {
Kailang Yange2757d52008-08-26 13:17:46 +02009249 .ops = &snd_hda_bind_sw,
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 snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009258 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9259 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9260 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9261 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9262 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9263 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009264 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009265 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009266 { } /* end */
9267};
9268
Takashi Iwaia9111322011-05-02 11:30:18 +02009269static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009270 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9271 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9272 {
9273 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9274 /* .name = "Capture Source", */
9275 .name = "Input Source",
9276 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009277 .info = alc_mux_enum_info,
9278 .get = alc_mux_enum_get,
9279 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009280 },
9281 { } /* end */
9282};
9283
Takashi Iwaia9111322011-05-02 11:30:18 +02009284static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009285 {
9286 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9287 .name = "Channel Mode",
9288 .info = alc_ch_mode_info,
9289 .get = alc_ch_mode_get,
9290 .put = alc_ch_mode_put,
9291 },
9292 { } /* end */
9293};
9294
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009295/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009296static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009297{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009298 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009299
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009300 spec->autocfg.hp_pins[0] = 0x15;
9301 spec->autocfg.speaker_pins[0] = 0x14;
9302 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009303 spec->automute = 1;
9304 spec->automute_mode = ALC_AUTOMUTE_AMP;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009305}
9306
Takashi Iwaia9111322011-05-02 11:30:18 +02009307static const struct hda_verb alc883_mitac_verbs[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009308 /* HP */
9309 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9310 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9311 /* Subwoofer */
9312 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9313 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9314
9315 /* enable unsolicited event */
9316 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9317 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9318
9319 { } /* end */
9320};
9321
Takashi Iwaia9111322011-05-02 11:30:18 +02009322static const struct hda_verb alc883_clevo_m540r_verbs[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309323 /* HP */
9324 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9325 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9326 /* Int speaker */
9327 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9328
9329 /* enable unsolicited event */
9330 /*
9331 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9332 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9333 */
9334
9335 { } /* end */
9336};
9337
Takashi Iwaia9111322011-05-02 11:30:18 +02009338static const struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009339 /* HP */
9340 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9341 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9342 /* Int speaker */
9343 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9344 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9345
9346 /* enable unsolicited event */
9347 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009348 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009349
9350 { } /* end */
9351};
9352
Takashi Iwaia9111322011-05-02 11:30:18 +02009353static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01009354 /* HP */
9355 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9356 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9357 /* Subwoofer */
9358 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9359 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9360
9361 /* enable unsolicited event */
9362 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9363
9364 { } /* end */
9365};
9366
Takashi Iwaia9111322011-05-02 11:30:18 +02009367static const struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009368 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9369 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9370
9371 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9372 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009373
David Heidelberger64a8be72009-06-08 16:15:18 +02009374/* Connect Line-Out side jack (SPDIF) to Side */
9375 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9376 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9377 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9378/* Connect Mic jack to CLFE */
9379 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9380 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9381 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9382/* Connect Line-in jack to Surround */
9383 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9384 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9385 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9386/* Connect HP out jack to Front */
9387 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9388 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9389 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009390
9391 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009392
9393 { } /* end */
9394};
9395
Takashi Iwaia9111322011-05-02 11:30:18 +02009396static const struct hda_verb alc883_lenovo_101e_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009397 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9398 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9399 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9400 { } /* end */
9401};
9402
Takashi Iwaia9111322011-05-02 11:30:18 +02009403static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009404 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9405 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9406 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9407 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9408 { } /* end */
9409};
9410
Takashi Iwaia9111322011-05-02 11:30:18 +02009411static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009412 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9413 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9414 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9415 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9416 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9417 { } /* end */
9418};
9419
Takashi Iwaia9111322011-05-02 11:30:18 +02009420static const struct hda_verb alc883_haier_w66_verbs[] = {
Kailang Yang189609a2007-08-20 11:31:23 +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
9424 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9425
9426 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9427 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9428 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9429 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9430 { } /* end */
9431};
9432
Takashi Iwaia9111322011-05-02 11:30:18 +02009433static const struct hda_verb alc888_lenovo_sky_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009434 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9435 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9436 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9437 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9438 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9439 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9440 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9441 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9442 { } /* end */
9443};
9444
Takashi Iwaia9111322011-05-02 11:30:18 +02009445static const struct hda_verb alc888_6st_dell_verbs[] = {
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009446 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9447 { }
9448};
9449
Takashi Iwaia9111322011-05-02 11:30:18 +02009450static const struct hda_verb alc883_vaiott_verbs[] = {
Guido Günther3e1647c52009-06-05 00:47:26 +02009451 /* HP */
9452 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9453 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9454
9455 /* enable unsolicited event */
9456 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9457
9458 { } /* end */
9459};
9460
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009461static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009462{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009463 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009464
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009465 spec->autocfg.hp_pins[0] = 0x1b;
9466 spec->autocfg.speaker_pins[0] = 0x14;
9467 spec->autocfg.speaker_pins[1] = 0x16;
9468 spec->autocfg.speaker_pins[2] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02009469 spec->automute = 1;
9470 spec->automute_mode = ALC_AUTOMUTE_AMP;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009471}
9472
Takashi Iwaia9111322011-05-02 11:30:18 +02009473static const struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009474 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009475 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9476 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009477 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009478 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009479};
9480
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009481/*
9482 * 2ch mode
9483 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009484static const struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009485 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9486 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9487 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9488 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009489 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009490};
9491
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009492/*
9493 * 4ch mode
9494 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009495static const struct hda_verb alc888_3st_hp_4ch_init[] = {
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009496 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9497 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9498 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9499 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9500 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9501 { } /* end */
9502};
9503
9504/*
9505 * 6ch mode
9506 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009507static const struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009508 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9509 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009510 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009511 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9512 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009513 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9514 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009515};
9516
Takashi Iwaia9111322011-05-02 11:30:18 +02009517static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009518 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009519 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009520 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009521};
9522
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009523static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009524{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009525 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009526
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009527 spec->autocfg.hp_pins[0] = 0x1b;
9528 spec->autocfg.line_out_pins[0] = 0x14;
9529 spec->autocfg.speaker_pins[0] = 0x15;
9530 spec->automute = 1;
9531 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009532}
9533
Kailang Yang272a5272007-05-14 11:00:38 +02009534/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc4271702010-11-29 07:42:59 +01009535static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009536{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009537 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009538
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009539 spec->autocfg.hp_pins[0] = 0x14;
9540 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009541 spec->automute = 1;
9542 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009543}
9544
Kailang Yangccc656c2006-10-17 12:32:26 +02009545/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009546#define alc883_targa_init_hook alc882_targa_init_hook
9547#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009548
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009549static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009550{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009551 struct alc_spec *spec = codec->spec;
9552
9553 spec->autocfg.hp_pins[0] = 0x15;
9554 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009555 spec->automute = 1;
9556 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009557}
9558
9559static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9560{
Takashi Iwaid922b512011-04-28 12:18:53 +02009561 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009562 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009563}
9564
9565static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009566 unsigned int res)
9567{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009568 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009569 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009570 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009571 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009572 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02009573 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009574 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009575 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009576}
9577
Jiang zhefb97dc62008-03-06 11:07:11 +01009578/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009579static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009580{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009581 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009582
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009583 spec->autocfg.hp_pins[0] = 0x14;
9584 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009585 spec->automute = 1;
9586 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhefb97dc62008-03-06 11:07:11 +01009587}
9588
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009589static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009590{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009591 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009592
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009593 spec->autocfg.hp_pins[0] = 0x1b;
9594 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009595 spec->automute = 1;
9596 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang189609a2007-08-20 11:31:23 +02009597}
9598
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009599static void alc883_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009600{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009601 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009602
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009603 spec->autocfg.hp_pins[0] = 0x1b;
9604 spec->autocfg.line_out_pins[0] = 0x14;
9605 spec->autocfg.speaker_pins[0] = 0x15;
9606 spec->automute = 1;
9607 spec->detect_line = 1;
9608 spec->automute_lines = 1;
9609 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009610}
9611
Takashi Iwai676a9b52007-08-16 15:23:35 +02009612/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009613static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009614{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009615 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009616
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009617 spec->autocfg.hp_pins[0] = 0x14;
9618 spec->autocfg.speaker_pins[0] = 0x15;
9619 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02009620 spec->automute = 1;
9621 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009622}
9623
Takashi Iwaia9111322011-05-02 11:30:18 +02009624static const struct hda_verb alc883_acer_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009625 /* HP Pin: output 0 (0x0c) */
9626 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9627 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9628 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9629 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009630 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9631 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009632 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009633 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9634 /* eanable EAPD on medion laptop */
9635 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9636 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009637 /* enable unsolicited event */
9638 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009639 { }
9640};
9641
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009642static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009643{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009644 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009645
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009646 spec->autocfg.hp_pins[0] = 0x1b;
9647 spec->autocfg.speaker_pins[0] = 0x14;
9648 spec->autocfg.speaker_pins[1] = 0x15;
9649 spec->autocfg.speaker_pins[2] = 0x16;
9650 spec->autocfg.speaker_pins[3] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009651 spec->automute = 1;
9652 spec->automute_mode = ALC_AUTOMUTE_AMP;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009653}
9654
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009655static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009656{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009657 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009658
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009659 spec->autocfg.hp_pins[0] = 0x1b;
9660 spec->autocfg.speaker_pins[0] = 0x14;
9661 spec->autocfg.speaker_pins[1] = 0x15;
9662 spec->autocfg.speaker_pins[2] = 0x16;
9663 spec->autocfg.speaker_pins[3] = 0x17;
9664 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02009665 spec->automute = 1;
9666 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009667}
9668
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009669static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c52009-06-05 00:47:26 +02009670{
9671 struct alc_spec *spec = codec->spec;
9672
9673 spec->autocfg.hp_pins[0] = 0x15;
9674 spec->autocfg.speaker_pins[0] = 0x14;
9675 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009676 spec->automute = 1;
9677 spec->automute_mode = ALC_AUTOMUTE_AMP;
Guido Günther3e1647c52009-06-05 00:47:26 +02009678}
9679
Takashi Iwaia9111322011-05-02 11:30:18 +02009680static const struct hda_verb alc888_asus_m90v_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009681 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9682 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9683 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9684 /* enable unsolicited event */
9685 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9686 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9687 { } /* end */
9688};
9689
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009690static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009691{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009692 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009693
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009694 spec->autocfg.hp_pins[0] = 0x1b;
9695 spec->autocfg.speaker_pins[0] = 0x14;
9696 spec->autocfg.speaker_pins[1] = 0x15;
9697 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009698 spec->ext_mic.pin = 0x18;
9699 spec->int_mic.pin = 0x19;
9700 spec->ext_mic.mux_idx = 0;
9701 spec->int_mic.mux_idx = 1;
9702 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +02009703 spec->automute = 1;
9704 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009705}
9706
Takashi Iwaia9111322011-05-02 11:30:18 +02009707static const struct hda_verb alc888_asus_eee1601_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009708 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9709 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9710 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9711 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9712 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9713 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9714 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9715 /* enable unsolicited event */
9716 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9717 { } /* end */
9718};
9719
Kailang Yange2757d52008-08-26 13:17:46 +02009720static void alc883_eee1601_inithook(struct hda_codec *codec)
9721{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009722 struct alc_spec *spec = codec->spec;
9723
9724 spec->autocfg.hp_pins[0] = 0x14;
9725 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02009726 alc_hp_automute(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009727}
9728
Takashi Iwaia9111322011-05-02 11:30:18 +02009729static const struct hda_verb alc889A_mb31_verbs[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009730 /* Init rear pin (used as headphone output) */
9731 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9732 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9733 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9734 /* Init line pin (used as output in 4ch and 6ch mode) */
9735 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9736 /* Init line 2 pin (used as headphone out by default) */
9737 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9738 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9739 { } /* end */
9740};
9741
9742/* Mute speakers according to the headphone jack state */
9743static void alc889A_mb31_automute(struct hda_codec *codec)
9744{
9745 unsigned int present;
9746
9747 /* Mute only in 2ch or 4ch mode */
9748 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9749 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009750 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009751 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9752 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9753 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9754 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9755 }
9756}
9757
9758static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9759{
9760 if ((res >> 26) == ALC880_HP_EVENT)
9761 alc889A_mb31_automute(codec);
9762}
9763
Takashi Iwai4953550a2009-06-30 15:28:30 +02009764
Takashi Iwaicb53c622007-08-10 17:21:45 +02009765#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai4953550a2009-06-30 15:28:30 +02009766#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009767#endif
9768
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009769/* pcm configuration: identical with ALC880 */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009770#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9771#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9772#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9773#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9774
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02009775static const hda_nid_t alc883_slave_dig_outs[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009776 ALC1200_DIGOUT_NID, 0,
9777};
9778
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02009779static const hda_nid_t alc1200_slave_dig_outs[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009780 ALC883_DIGOUT_NID, 0,
9781};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009782
9783/*
9784 * configuration and preset
9785 */
Takashi Iwaiea734962011-01-17 11:29:34 +01009786static const char * const alc882_models[ALC882_MODEL_LAST] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009787 [ALC882_3ST_DIG] = "3stack-dig",
9788 [ALC882_6ST_DIG] = "6stack-dig",
9789 [ALC882_ARIMA] = "arima",
9790 [ALC882_W2JC] = "w2jc",
9791 [ALC882_TARGA] = "targa",
9792 [ALC882_ASUS_A7J] = "asus-a7j",
9793 [ALC882_ASUS_A7M] = "asus-a7m",
9794 [ALC885_MACPRO] = "macpro",
9795 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009796 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009797 [ALC885_MBA21] = "mba21",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009798 [ALC885_MBP3] = "mbp3",
9799 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009800 [ALC885_IMAC91] = "imac91",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009801 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009802 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9803 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009804 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009805 [ALC883_TARGA_DIG] = "targa-dig",
9806 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009807 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009808 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009809 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009810 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009811 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009812 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009813 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009814 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009815 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009816 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009817 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009818 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9819 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009820 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009821 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009822 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009823 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009824 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309825 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009826 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009827 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009828 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009829 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009830 [ALC889A_INTEL] = "intel-alc889a",
9831 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009832 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009833 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c52009-06-05 00:47:26 +02009834 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai4953550a2009-06-30 15:28:30 +02009835 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009836};
9837
Takashi Iwaia9111322011-05-02 11:30:18 +02009838static const struct snd_pci_quirk alc882_cfg_tbl[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009839 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9840
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009841 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009842 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009843 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009844 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9845 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009846 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009847 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9848 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009849 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009850 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009851 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9852 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009853 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9854 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009855 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9856 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009857 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009858 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009859 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009860 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009861 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9862 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009863 /* default Acer -- disabled as it causes more problems.
9864 * model=auto should work fine now
9865 */
9866 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai4953550a2009-06-30 15:28:30 +02009867
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009868 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009869
Lucas De Marchi25985ed2011-03-30 22:57:33 -03009870 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009871 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9872 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009873 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009874 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009875 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009876
9877 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9878 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9879 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009880 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009881 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9882 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9883 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009884 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009885 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009886 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009887 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009888
9889 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009890 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009891 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009892 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009893 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9894 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009895 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009896 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwaiebb47242011-05-02 10:37:29 +02009897 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009898
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009899 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9900 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9901 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009902 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009903 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009904 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009905 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009906 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009907 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9908 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9909 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9910 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9911 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9912 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009913 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009914 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9915 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9916 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009917 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009918 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009919 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9920 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009921 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009922 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009923 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009924 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009925 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009926 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009927 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009928 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009929 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009930
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009931 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009932 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009933 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9934 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309935 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009936 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009937 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009938 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009939 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009940 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009941 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009942 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009943 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009944 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009945 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009946 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9947 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009948 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +01009949 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009950 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009951 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009952
Jiang zhe17bba1b2008-06-04 12:11:07 +02009953 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9954 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009955 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009956 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9957 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9958 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009959 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009960
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009961 {}
9962};
9963
Takashi Iwai4953550a2009-06-30 15:28:30 +02009964/* codec SSID table for Intel Mac */
Takashi Iwaia9111322011-05-02 11:30:18 +02009965static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009966 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9967 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9968 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9969 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9970 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9971 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9972 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009973 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009974 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009975 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009976 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009977 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9978 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9979 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009980 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009981 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009982 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009983 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9984 * so apparently no perfect solution yet
Takashi Iwai4953550a2009-06-30 15:28:30 +02009985 */
9986 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009987 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009988 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai4953550a2009-06-30 15:28:30 +02009989 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009990};
9991
Takashi Iwaia9111322011-05-02 11:30:18 +02009992static const struct alc_config_preset alc882_presets[] = {
Takashi Iwai4953550a2009-06-30 15:28:30 +02009993 [ALC882_3ST_DIG] = {
9994 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009995 .init_verbs = { alc882_base_init_verbs,
9996 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +02009997 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9998 .dac_nids = alc882_dac_nids,
9999 .dig_out_nid = ALC882_DIGOUT_NID,
10000 .dig_in_nid = ALC882_DIGIN_NID,
10001 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10002 .channel_mode = alc882_ch_modes,
10003 .need_dac_fix = 1,
10004 .input_mux = &alc882_capture_source,
10005 },
10006 [ALC882_6ST_DIG] = {
10007 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010008 .init_verbs = { alc882_base_init_verbs,
10009 alc882_adc1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010010 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10011 .dac_nids = alc882_dac_nids,
10012 .dig_out_nid = ALC882_DIGOUT_NID,
10013 .dig_in_nid = ALC882_DIGIN_NID,
10014 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10015 .channel_mode = alc882_sixstack_modes,
10016 .input_mux = &alc882_capture_source,
10017 },
10018 [ALC882_ARIMA] = {
10019 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010020 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10021 alc882_eapd_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010022 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10023 .dac_nids = alc882_dac_nids,
10024 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10025 .channel_mode = alc882_sixstack_modes,
10026 .input_mux = &alc882_capture_source,
10027 },
10028 [ALC882_W2JC] = {
10029 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010030 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10031 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010032 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10033 .dac_nids = alc882_dac_nids,
10034 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10035 .channel_mode = alc880_threestack_modes,
10036 .need_dac_fix = 1,
10037 .input_mux = &alc882_capture_source,
10038 .dig_out_nid = ALC882_DIGOUT_NID,
10039 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010040 [ALC885_MBA21] = {
10041 .mixers = { alc885_mba21_mixer },
10042 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
10043 .num_dacs = 2,
10044 .dac_nids = alc882_dac_nids,
10045 .channel_mode = alc885_mba21_ch_modes,
10046 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10047 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010048 .unsol_event = alc_sku_unsol_event,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010049 .setup = alc885_mba21_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010050 .init_hook = alc_hp_automute,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010051 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010052 [ALC885_MBP3] = {
10053 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
10054 .init_verbs = { alc885_mbp3_init_verbs,
10055 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010056 .num_dacs = 2,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010057 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010058 .hp_nid = 0x04,
10059 .channel_mode = alc885_mbp_4ch_modes,
10060 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010061 .input_mux = &alc882_capture_source,
10062 .dig_out_nid = ALC882_DIGOUT_NID,
10063 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010064 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010065 .setup = alc885_mbp3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010066 .init_hook = alc_hp_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010067 },
10068 [ALC885_MB5] = {
10069 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
10070 .init_verbs = { alc885_mb5_init_verbs,
10071 alc880_gpio1_init_verbs },
10072 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10073 .dac_nids = alc882_dac_nids,
10074 .channel_mode = alc885_mb5_6ch_modes,
10075 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10076 .input_mux = &mb5_capture_source,
10077 .dig_out_nid = ALC882_DIGOUT_NID,
10078 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010079 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010080 .setup = alc885_mb5_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010081 .init_hook = alc_hp_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010082 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010083 [ALC885_MACMINI3] = {
10084 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10085 .init_verbs = { alc885_macmini3_init_verbs,
10086 alc880_gpio1_init_verbs },
10087 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10088 .dac_nids = alc882_dac_nids,
10089 .channel_mode = alc885_macmini3_6ch_modes,
10090 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10091 .input_mux = &macmini3_capture_source,
10092 .dig_out_nid = ALC882_DIGOUT_NID,
10093 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010094 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010095 .setup = alc885_macmini3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010096 .init_hook = alc_hp_automute,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010097 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010098 [ALC885_MACPRO] = {
10099 .mixers = { alc882_macpro_mixer },
10100 .init_verbs = { alc882_macpro_init_verbs },
10101 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10102 .dac_nids = alc882_dac_nids,
10103 .dig_out_nid = ALC882_DIGOUT_NID,
10104 .dig_in_nid = ALC882_DIGIN_NID,
10105 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10106 .channel_mode = alc882_ch_modes,
10107 .input_mux = &alc882_capture_source,
10108 .init_hook = alc885_macpro_init_hook,
10109 },
10110 [ALC885_IMAC24] = {
10111 .mixers = { alc885_imac24_mixer },
10112 .init_verbs = { alc885_imac24_init_verbs },
10113 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10114 .dac_nids = alc882_dac_nids,
10115 .dig_out_nid = ALC882_DIGOUT_NID,
10116 .dig_in_nid = ALC882_DIGIN_NID,
10117 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10118 .channel_mode = alc882_ch_modes,
10119 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010120 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010121 .setup = alc885_imac24_setup,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010122 .init_hook = alc885_imac24_init_hook,
10123 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010124 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010125 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010126 .init_verbs = { alc885_imac91_init_verbs,
10127 alc880_gpio1_init_verbs },
10128 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10129 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010130 .channel_mode = alc885_mba21_ch_modes,
10131 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10132 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010133 .dig_out_nid = ALC882_DIGOUT_NID,
10134 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010135 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010136 .setup = alc885_imac91_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010137 .init_hook = alc_hp_automute,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010138 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010139 [ALC882_TARGA] = {
10140 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010141 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010142 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +020010143 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10144 .dac_nids = alc882_dac_nids,
10145 .dig_out_nid = ALC882_DIGOUT_NID,
10146 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10147 .adc_nids = alc882_adc_nids,
10148 .capsrc_nids = alc882_capsrc_nids,
10149 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10150 .channel_mode = alc882_3ST_6ch_modes,
10151 .need_dac_fix = 1,
10152 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010153 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010154 .setup = alc882_targa_setup,
10155 .init_hook = alc882_targa_automute,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010156 },
10157 [ALC882_ASUS_A7J] = {
10158 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010159 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10160 alc882_asus_a7j_verbs},
Takashi Iwai4953550a2009-06-30 15:28:30 +020010161 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10162 .dac_nids = alc882_dac_nids,
10163 .dig_out_nid = ALC882_DIGOUT_NID,
10164 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10165 .adc_nids = alc882_adc_nids,
10166 .capsrc_nids = alc882_capsrc_nids,
10167 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10168 .channel_mode = alc882_3ST_6ch_modes,
10169 .need_dac_fix = 1,
10170 .input_mux = &alc882_capture_source,
10171 },
10172 [ALC882_ASUS_A7M] = {
10173 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010174 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10175 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010176 alc882_asus_a7m_verbs },
10177 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10178 .dac_nids = alc882_dac_nids,
10179 .dig_out_nid = ALC882_DIGOUT_NID,
10180 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10181 .channel_mode = alc880_threestack_modes,
10182 .need_dac_fix = 1,
10183 .input_mux = &alc882_capture_source,
10184 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010185 [ALC883_3ST_2ch_DIG] = {
10186 .mixers = { alc883_3ST_2ch_mixer },
10187 .init_verbs = { alc883_init_verbs },
10188 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10189 .dac_nids = alc883_dac_nids,
10190 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010191 .dig_in_nid = ALC883_DIGIN_NID,
10192 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10193 .channel_mode = alc883_3ST_2ch_modes,
10194 .input_mux = &alc883_capture_source,
10195 },
10196 [ALC883_3ST_6ch_DIG] = {
10197 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10198 .init_verbs = { alc883_init_verbs },
10199 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10200 .dac_nids = alc883_dac_nids,
10201 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010202 .dig_in_nid = ALC883_DIGIN_NID,
10203 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10204 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010205 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010206 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010207 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010208 [ALC883_3ST_6ch] = {
10209 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10210 .init_verbs = { alc883_init_verbs },
10211 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10212 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010213 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10214 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010215 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010216 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010217 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010218 [ALC883_3ST_6ch_INTEL] = {
10219 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10220 .init_verbs = { alc883_init_verbs },
10221 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10222 .dac_nids = alc883_dac_nids,
10223 .dig_out_nid = ALC883_DIGOUT_NID,
10224 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010225 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010226 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10227 .channel_mode = alc883_3ST_6ch_intel_modes,
10228 .need_dac_fix = 1,
10229 .input_mux = &alc883_3stack_6ch_intel,
10230 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010231 [ALC889A_INTEL] = {
10232 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010233 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10234 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010235 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10236 .dac_nids = alc883_dac_nids,
10237 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10238 .adc_nids = alc889_adc_nids,
10239 .dig_out_nid = ALC883_DIGOUT_NID,
10240 .dig_in_nid = ALC883_DIGIN_NID,
10241 .slave_dig_outs = alc883_slave_dig_outs,
10242 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10243 .channel_mode = alc889_8ch_intel_modes,
10244 .capsrc_nids = alc889_capsrc_nids,
10245 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010246 .setup = alc889_automute_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010247 .init_hook = alc_hp_automute,
10248 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010249 .need_dac_fix = 1,
10250 },
10251 [ALC889_INTEL] = {
10252 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10253 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010254 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010255 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10256 .dac_nids = alc883_dac_nids,
10257 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10258 .adc_nids = alc889_adc_nids,
10259 .dig_out_nid = ALC883_DIGOUT_NID,
10260 .dig_in_nid = ALC883_DIGIN_NID,
10261 .slave_dig_outs = alc883_slave_dig_outs,
10262 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10263 .channel_mode = alc889_8ch_intel_modes,
10264 .capsrc_nids = alc889_capsrc_nids,
10265 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010266 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010267 .init_hook = alc889_intel_init_hook,
Takashi Iwaid922b512011-04-28 12:18:53 +020010268 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010269 .need_dac_fix = 1,
10270 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010271 [ALC883_6ST_DIG] = {
10272 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10273 .init_verbs = { alc883_init_verbs },
10274 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10275 .dac_nids = alc883_dac_nids,
10276 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010277 .dig_in_nid = ALC883_DIGIN_NID,
10278 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10279 .channel_mode = alc883_sixstack_modes,
10280 .input_mux = &alc883_capture_source,
10281 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010282 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010283 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010284 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10285 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010286 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10287 .dac_nids = alc883_dac_nids,
10288 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010289 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10290 .channel_mode = alc883_3ST_6ch_modes,
10291 .need_dac_fix = 1,
10292 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010293 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010294 .setup = alc882_targa_setup,
10295 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010296 },
10297 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010298 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010299 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10300 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010301 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10302 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010303 .adc_nids = alc883_adc_nids_alt,
10304 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010305 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010306 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010307 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10308 .channel_mode = alc883_3ST_2ch_modes,
10309 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010310 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010311 .setup = alc882_targa_setup,
10312 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010313 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010314 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010315 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10316 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010317 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010318 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010319 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10320 .dac_nids = alc883_dac_nids,
10321 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10322 .adc_nids = alc883_adc_nids_rev,
10323 .capsrc_nids = alc883_capsrc_nids_rev,
10324 .dig_out_nid = ALC883_DIGOUT_NID,
10325 .dig_in_nid = ALC883_DIGIN_NID,
10326 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10327 .channel_mode = alc883_4ST_8ch_modes,
10328 .need_dac_fix = 1,
10329 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010330 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010331 .setup = alc882_targa_setup,
10332 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010333 },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010334 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010335 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010336 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10337 * and the headphone jack. Turn this on and rely on the
10338 * standard mute methods whenever the user wants to turn
10339 * these outputs off.
10340 */
10341 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10342 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10343 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b92006-08-22 13:31:58 +020010344 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10345 .channel_mode = alc883_3ST_2ch_modes,
10346 .input_mux = &alc883_capture_source,
10347 },
Tobin Davis2880a862007-08-07 11:50:26 +020010348 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010349 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010350 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010351 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10352 .dac_nids = alc883_dac_nids,
10353 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010354 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10355 .channel_mode = alc883_3ST_2ch_modes,
10356 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010357 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010358 .setup = alc883_acer_aspire_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010359 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010360 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010361 [ALC888_ACER_ASPIRE_4930G] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +010010362 .mixers = { alc888_acer_aspire_4930g_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010363 alc883_chmode_mixer },
10364 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10365 alc888_acer_aspire_4930g_verbs },
10366 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10367 .dac_nids = alc883_dac_nids,
10368 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10369 .adc_nids = alc883_adc_nids_rev,
10370 .capsrc_nids = alc883_capsrc_nids_rev,
10371 .dig_out_nid = ALC883_DIGOUT_NID,
10372 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10373 .channel_mode = alc883_3ST_6ch_modes,
10374 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010375 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010376 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010377 ARRAY_SIZE(alc888_2_capture_sources),
10378 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010379 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010380 .setup = alc888_acer_aspire_4930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010381 .init_hook = alc_hp_automute,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010382 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010383 [ALC888_ACER_ASPIRE_6530G] = {
10384 .mixers = { alc888_acer_aspire_6530_mixer },
10385 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10386 alc888_acer_aspire_6530g_verbs },
10387 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10388 .dac_nids = alc883_dac_nids,
10389 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10390 .adc_nids = alc883_adc_nids_rev,
10391 .capsrc_nids = alc883_capsrc_nids_rev,
10392 .dig_out_nid = ALC883_DIGOUT_NID,
10393 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10394 .channel_mode = alc883_3ST_2ch_modes,
10395 .num_mux_defs =
10396 ARRAY_SIZE(alc888_2_capture_sources),
10397 .input_mux = alc888_acer_aspire_6530_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010398 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010399 .setup = alc888_acer_aspire_6530g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010400 .init_hook = alc_hp_automute,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010401 },
Hector Martin3b315d72009-06-02 10:54:19 +020010402 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010403 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010404 alc883_chmode_mixer },
10405 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010406 alc889_acer_aspire_8930g_verbs,
10407 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010408 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10409 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010410 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10411 .adc_nids = alc889_adc_nids,
10412 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010413 .dig_out_nid = ALC883_DIGOUT_NID,
10414 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10415 .channel_mode = alc883_3ST_6ch_modes,
10416 .need_dac_fix = 1,
10417 .const_channel_count = 6,
10418 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010419 ARRAY_SIZE(alc889_capture_sources),
10420 .input_mux = alc889_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010421 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010422 .setup = alc889_acer_aspire_8930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010423 .init_hook = alc_hp_automute,
Hector Martinf5de24b2009-12-20 22:51:31 +010010424#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010425 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010426#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010427 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010428 [ALC888_ACER_ASPIRE_7730G] = {
10429 .mixers = { alc883_3ST_6ch_mixer,
10430 alc883_chmode_mixer },
10431 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10432 alc888_acer_aspire_7730G_verbs },
10433 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10434 .dac_nids = alc883_dac_nids,
10435 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10436 .adc_nids = alc883_adc_nids_rev,
10437 .capsrc_nids = alc883_capsrc_nids_rev,
10438 .dig_out_nid = ALC883_DIGOUT_NID,
10439 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10440 .channel_mode = alc883_3ST_6ch_modes,
10441 .need_dac_fix = 1,
10442 .const_channel_count = 6,
10443 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010444 .unsol_event = alc_sku_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010445 .setup = alc888_acer_aspire_7730g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010446 .init_hook = alc_hp_automute,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010447 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010448 [ALC883_MEDION] = {
10449 .mixers = { alc883_fivestack_mixer,
10450 alc883_chmode_mixer },
10451 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010452 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010453 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10454 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010455 .adc_nids = alc883_adc_nids_alt,
10456 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010457 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010458 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10459 .channel_mode = alc883_sixstack_modes,
10460 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010461 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010462 [ALC883_MEDION_WIM2160] = {
10463 .mixers = { alc883_medion_wim2160_mixer },
10464 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10465 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10466 .dac_nids = alc883_dac_nids,
10467 .dig_out_nid = ALC883_DIGOUT_NID,
10468 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10469 .adc_nids = alc883_adc_nids,
10470 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10471 .channel_mode = alc883_3ST_2ch_modes,
10472 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010473 .unsol_event = alc_sku_unsol_event,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010474 .setup = alc883_medion_wim2160_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010475 .init_hook = alc_hp_automute,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010476 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010477 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010478 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010479 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10480 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10481 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010482 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10483 .channel_mode = alc883_3ST_2ch_modes,
10484 .input_mux = &alc883_capture_source,
10485 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010486 [ALC883_CLEVO_M540R] = {
10487 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10488 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10489 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10490 .dac_nids = alc883_dac_nids,
10491 .dig_out_nid = ALC883_DIGOUT_NID,
10492 .dig_in_nid = ALC883_DIGIN_NID,
10493 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10494 .channel_mode = alc883_3ST_6ch_clevo_modes,
10495 .need_dac_fix = 1,
10496 .input_mux = &alc883_capture_source,
10497 /* This machine has the hardware HP auto-muting, thus
10498 * we need no software mute via unsol event
10499 */
10500 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010501 [ALC883_CLEVO_M720] = {
10502 .mixers = { alc883_clevo_m720_mixer },
10503 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010504 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10505 .dac_nids = alc883_dac_nids,
10506 .dig_out_nid = ALC883_DIGOUT_NID,
10507 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10508 .channel_mode = alc883_3ST_2ch_modes,
10509 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010510 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010511 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010512 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010513 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010514 [ALC883_LENOVO_101E_2ch] = {
10515 .mixers = { alc883_lenovo_101e_2ch_mixer},
10516 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10517 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10518 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010519 .adc_nids = alc883_adc_nids_alt,
10520 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010521 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010522 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10523 .channel_mode = alc883_3ST_2ch_modes,
10524 .input_mux = &alc883_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010525 .setup = alc883_lenovo_101e_setup,
10526 .unsol_event = alc_sku_unsol_event,
10527 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010528 },
Kailang Yang272a5272007-05-14 11:00:38 +020010529 [ALC883_LENOVO_NB0763] = {
10530 .mixers = { alc883_lenovo_nb0763_mixer },
10531 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10532 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10533 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010534 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10535 .channel_mode = alc883_3ST_2ch_modes,
10536 .need_dac_fix = 1,
10537 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010538 .unsol_event = alc_sku_unsol_event,
Takashi Iwaidc4271702010-11-29 07:42:59 +010010539 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010540 .init_hook = alc_hp_automute,
Kailang Yang272a5272007-05-14 11:00:38 +020010541 },
10542 [ALC888_LENOVO_MS7195_DIG] = {
10543 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10544 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10545 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10546 .dac_nids = alc883_dac_nids,
10547 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010548 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10549 .channel_mode = alc883_3ST_6ch_modes,
10550 .need_dac_fix = 1,
10551 .input_mux = &alc883_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010552 .unsol_event = alc_sku_unsol_event,
10553 .setup = alc888_lenovo_ms7195_setup,
10554 .init_hook = alc_inithook,
Kailang Yang189609a2007-08-20 11:31:23 +020010555 },
10556 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010557 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010558 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10559 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10560 .dac_nids = alc883_dac_nids,
10561 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010562 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10563 .channel_mode = alc883_3ST_2ch_modes,
10564 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010565 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010566 .setup = alc883_haier_w66_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010567 .init_hook = alc_hp_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010568 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010569 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010570 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010571 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010572 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10573 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010574 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10575 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010576 .need_dac_fix = 1,
10577 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010578 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010579 .setup = alc888_3st_hp_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010580 .init_hook = alc_hp_automute,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010581 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010582 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010583 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010584 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10585 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10586 .dac_nids = alc883_dac_nids,
10587 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010588 .dig_in_nid = ALC883_DIGIN_NID,
10589 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10590 .channel_mode = alc883_sixstack_modes,
10591 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010592 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010593 .setup = alc888_6st_dell_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010594 .init_hook = alc_hp_automute,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010595 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010596 [ALC883_MITAC] = {
10597 .mixers = { alc883_mitac_mixer },
10598 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10599 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10600 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010601 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10602 .channel_mode = alc883_3ST_2ch_modes,
10603 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010604 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010605 .setup = alc883_mitac_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010606 .init_hook = alc_hp_automute,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010607 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010608 [ALC883_FUJITSU_PI2515] = {
10609 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10610 .init_verbs = { alc883_init_verbs,
10611 alc883_2ch_fujitsu_pi2515_verbs},
10612 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10613 .dac_nids = alc883_dac_nids,
10614 .dig_out_nid = ALC883_DIGOUT_NID,
10615 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10616 .channel_mode = alc883_3ST_2ch_modes,
10617 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010618 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010619 .setup = alc883_2ch_fujitsu_pi2515_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010620 .init_hook = alc_hp_automute,
Jiang zhefb97dc62008-03-06 11:07:11 +010010621 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010622 [ALC888_FUJITSU_XA3530] = {
10623 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10624 .init_verbs = { alc883_init_verbs,
10625 alc888_fujitsu_xa3530_verbs },
10626 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10627 .dac_nids = alc883_dac_nids,
10628 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10629 .adc_nids = alc883_adc_nids_rev,
10630 .capsrc_nids = alc883_capsrc_nids_rev,
10631 .dig_out_nid = ALC883_DIGOUT_NID,
10632 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10633 .channel_mode = alc888_4ST_8ch_intel_modes,
10634 .num_mux_defs =
10635 ARRAY_SIZE(alc888_2_capture_sources),
10636 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010637 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010638 .setup = alc888_fujitsu_xa3530_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010639 .init_hook = alc_hp_automute,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010640 },
Kailang Yange2757d52008-08-26 13:17:46 +020010641 [ALC888_LENOVO_SKY] = {
10642 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10643 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10644 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10645 .dac_nids = alc883_dac_nids,
10646 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010647 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10648 .channel_mode = alc883_sixstack_modes,
10649 .need_dac_fix = 1,
10650 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010651 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010652 .setup = alc888_lenovo_sky_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010653 .init_hook = alc_hp_automute,
Kailang Yange2757d52008-08-26 13:17:46 +020010654 },
10655 [ALC888_ASUS_M90V] = {
10656 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10657 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10658 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10659 .dac_nids = alc883_dac_nids,
10660 .dig_out_nid = ALC883_DIGOUT_NID,
10661 .dig_in_nid = ALC883_DIGIN_NID,
10662 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10663 .channel_mode = alc883_3ST_6ch_modes,
10664 .need_dac_fix = 1,
10665 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010666 .unsol_event = alc_sku_unsol_event,
10667 .setup = alc883_mode2_setup,
10668 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010669 },
10670 [ALC888_ASUS_EEE1601] = {
10671 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010672 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010673 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10674 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10675 .dac_nids = alc883_dac_nids,
10676 .dig_out_nid = ALC883_DIGOUT_NID,
10677 .dig_in_nid = ALC883_DIGIN_NID,
10678 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10679 .channel_mode = alc883_3ST_2ch_modes,
10680 .need_dac_fix = 1,
10681 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010682 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010683 .init_hook = alc883_eee1601_inithook,
10684 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010685 [ALC1200_ASUS_P5Q] = {
10686 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10687 .init_verbs = { alc883_init_verbs },
10688 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10689 .dac_nids = alc883_dac_nids,
10690 .dig_out_nid = ALC1200_DIGOUT_NID,
10691 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010692 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010693 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10694 .channel_mode = alc883_sixstack_modes,
10695 .input_mux = &alc883_capture_source,
10696 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010697 [ALC889A_MB31] = {
10698 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10699 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10700 alc880_gpio1_init_verbs },
10701 .adc_nids = alc883_adc_nids,
10702 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010703 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010704 .dac_nids = alc883_dac_nids,
10705 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10706 .channel_mode = alc889A_mb31_6ch_modes,
10707 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10708 .input_mux = &alc889A_mb31_capture_source,
10709 .dig_out_nid = ALC883_DIGOUT_NID,
10710 .unsol_event = alc889A_mb31_unsol_event,
10711 .init_hook = alc889A_mb31_automute,
10712 },
Guido Günther3e1647c52009-06-05 00:47:26 +020010713 [ALC883_SONY_VAIO_TT] = {
10714 .mixers = { alc883_vaiott_mixer },
10715 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10716 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10717 .dac_nids = alc883_dac_nids,
10718 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10719 .channel_mode = alc883_3ST_2ch_modes,
10720 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010721 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010722 .setup = alc883_vaiott_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010723 .init_hook = alc_hp_automute,
Guido Günther3e1647c52009-06-05 00:47:26 +020010724 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010725};
10726
10727
10728/*
Takashi Iwai4953550a2009-06-30 15:28:30 +020010729 * Pin config fixes
10730 */
10731enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010732 PINFIX_ABIT_AW9D_MAX,
David Henningsson32eea382011-03-04 13:37:50 +010010733 PINFIX_LENOVO_Y530,
Takashi Iwai954a29c2010-07-30 10:55:44 +020010734 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010735 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai4953550a2009-06-30 15:28:30 +020010736};
10737
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010738static const struct alc_fixup alc882_fixups[] = {
10739 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010740 .type = ALC_FIXUP_PINS,
10741 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010742 { 0x15, 0x01080104 }, /* side */
10743 { 0x16, 0x01011012 }, /* rear */
10744 { 0x17, 0x01016011 }, /* clfe */
10745 { }
10746 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010747 },
David Henningsson32eea382011-03-04 13:37:50 +010010748 [PINFIX_LENOVO_Y530] = {
10749 .type = ALC_FIXUP_PINS,
10750 .v.pins = (const struct alc_pincfg[]) {
10751 { 0x15, 0x99130112 }, /* rear int speakers */
10752 { 0x16, 0x99130111 }, /* subwoofer */
10753 { }
10754 }
10755 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010756 [PINFIX_PB_M5210] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010757 .type = ALC_FIXUP_VERBS,
10758 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010759 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10760 {}
10761 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010762 },
David Henningssonc3d226a2010-10-14 15:42:08 +020010763 [PINFIX_ACER_ASPIRE_7736] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010764 .type = ALC_FIXUP_SKU,
10765 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonc3d226a2010-10-14 15:42:08 +020010766 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020010767};
10768
Takashi Iwaia9111322011-05-02 11:30:18 +020010769static const struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010770 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
David Henningsson32eea382011-03-04 13:37:50 +010010771 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010772 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020010773 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai4953550a2009-06-30 15:28:30 +020010774 {}
10775};
10776
10777/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010778 * BIOS auto configuration
10779 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010780static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10781 const struct auto_pin_cfg *cfg)
10782{
10783 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10784}
10785
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020010786#define alc882_auto_init_analog_input alc880_auto_init_analog_input
Takashi Iwai4953550a2009-06-30 15:28:30 +020010787
10788static void alc882_auto_init_input_src(struct hda_codec *codec)
10789{
10790 struct alc_spec *spec = codec->spec;
10791 int c;
10792
10793 for (c = 0; c < spec->num_adc_nids; c++) {
Takashi Iwai4953550a2009-06-30 15:28:30 +020010794 hda_nid_t nid = spec->capsrc_nids[c];
10795 unsigned int mux_idx;
10796 const struct hda_input_mux *imux;
10797 int conns, mute, idx, item;
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020010798 unsigned int wid_type;
Takashi Iwai4953550a2009-06-30 15:28:30 +020010799
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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-06-30 15:28:30 +020010853 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010010854 const char *prev_label = NULL;
Takashi Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai4953550a2009-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 Iwai05f5f472009-08-25 13:10:18 +020010912 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10913 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
Kailang Yang6227cdc2010-02-25 08:36:52 +010010926 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010927
10928 err = alc_auto_add_mic_boost(codec);
10929 if (err < 0)
10930 return err;
10931
Takashi Iwai776e1842007-08-29 15:07:11 +020010932 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010933}
10934
10935/* additional initialization for auto-configuration model */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010936static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010937{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010938 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010939 alc_auto_init_multi_out(codec);
10940 alc_auto_init_extra_out(codec);
Takashi Iwai4953550a2009-06-30 15:28:30 +020010941 alc882_auto_init_analog_input(codec);
10942 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010943 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010944 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010945 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010946}
10947
Takashi Iwai4953550a2009-06-30 15:28:30 +020010948static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010949{
10950 struct alc_spec *spec;
10951 int err, board_config;
10952
10953 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10954 if (spec == NULL)
10955 return -ENOMEM;
10956
10957 codec->spec = spec;
10958
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020010959 spec->mixer_nid = 0x0b;
10960
Takashi Iwai4953550a2009-06-30 15:28:30 +020010961 switch (codec->vendor_id) {
10962 case 0x10ec0882:
10963 case 0x10ec0885:
10964 break;
10965 default:
10966 /* ALC883 and variants */
10967 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10968 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010969 }
10970
Takashi Iwai4953550a2009-06-30 15:28:30 +020010971 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10972 alc882_models,
10973 alc882_cfg_tbl);
10974
10975 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10976 board_config = snd_hda_check_board_codec_sid_config(codec,
10977 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10978
10979 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010980 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai4953550a2009-06-30 15:28:30 +020010981 codec->chip_name);
10982 board_config = ALC882_AUTO;
10983 }
10984
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010985 if (board_config == ALC882_AUTO) {
10986 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
10987 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
10988 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020010989
David Henningsson90622912010-10-14 14:50:18 +020010990 alc_auto_parse_customize_define(codec);
10991
Takashi Iwai4953550a2009-06-30 15:28:30 +020010992 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010993 /* automatic parse from the BIOS config */
Takashi Iwai4953550a2009-06-30 15:28:30 +020010994 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010995 if (err < 0) {
10996 alc_free(codec);
10997 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010998 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010999 printk(KERN_INFO
11000 "hda_codec: Cannot set up configuration "
11001 "from BIOS. Using base mode...\n");
Takashi Iwai4953550a2009-06-30 15:28:30 +020011002 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011003 }
11004 }
11005
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011006 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020011007 err = snd_hda_attach_beep_device(codec, 0x1);
11008 if (err < 0) {
11009 alc_free(codec);
11010 return err;
11011 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011012 }
11013
Takashi Iwai4953550a2009-06-30 15:28:30 +020011014 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011015 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011016
Takashi Iwai4953550a2009-06-30 15:28:30 +020011017 spec->stream_analog_playback = &alc882_pcm_analog_playback;
11018 spec->stream_analog_capture = &alc882_pcm_analog_capture;
11019 /* FIXME: setup DAC5 */
11020 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
11021 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
11022
11023 spec->stream_digital_playback = &alc882_pcm_digital_playback;
11024 spec->stream_digital_capture = &alc882_pcm_digital_capture;
11025
Takashi Iwai4953550a2009-06-30 15:28:30 +020011026 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011027 int i, j;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011028 spec->num_adc_nids = 0;
11029 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011030 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011031 hda_nid_t cap;
11032 hda_nid_t nid = alc882_adc_nids[i];
11033 unsigned int wcap = get_wcaps(codec, nid);
11034 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020011035 wcap = get_wcaps_type(wcap);
Takashi Iwai4953550a2009-06-30 15:28:30 +020011036 if (wcap != AC_WID_AUD_IN)
11037 continue;
11038 spec->private_adc_nids[spec->num_adc_nids] = nid;
11039 err = snd_hda_get_connections(codec, nid, &cap, 1);
11040 if (err < 0)
11041 continue;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020011042 err = snd_hda_get_conn_list(codec, cap, NULL);
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011043 if (err < 0)
11044 continue;
11045 for (j = 0; j < imux->num_items; j++)
11046 if (imux->items[j].index >= err)
11047 break;
11048 if (j < imux->num_items)
11049 continue;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011050 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
11051 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011052 }
Takashi Iwai4953550a2009-06-30 15:28:30 +020011053 spec->adc_nids = spec->private_adc_nids;
11054 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020011055 }
11056
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011057 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011058
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011059 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011060 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011061
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011062 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011063
Takashi Iwai2134ea42008-01-10 16:53:55 +010011064 spec->vmaster_nid = 0x0c;
11065
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011066 codec->patch_ops = alc_patch_ops;
Takashi Iwai4953550a2009-06-30 15:28:30 +020011067 if (board_config == ALC882_AUTO)
11068 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011069
11070 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011071#ifdef CONFIG_SND_HDA_POWER_SAVE
11072 if (!spec->loopback.amplist)
Takashi Iwai4953550a2009-06-30 15:28:30 +020011073 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011074#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011075
11076 return 0;
11077}
11078
Takashi Iwai4953550a2009-06-30 15:28:30 +020011079
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011080/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011081 * ALC262 support
11082 */
11083
11084#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11085#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11086
11087#define alc262_dac_nids alc260_dac_nids
11088#define alc262_adc_nids alc882_adc_nids
11089#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011090#define alc262_capsrc_nids alc882_capsrc_nids
11091#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011092
11093#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011094#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011095
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011096static const hda_nid_t alc262_dmic_adc_nids[1] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011097 /* ADC0 */
11098 0x09
11099};
11100
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011101static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
Kailang Yang4e555fe2008-08-26 13:05:55 +020011102
Takashi Iwaia9111322011-05-02 11:30:18 +020011103static const struct snd_kcontrol_new alc262_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011104 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11105 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11106 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11107 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11108 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11109 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11110 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11111 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011112 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011113 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11114 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011115 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011116 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11117 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11118 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11119 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011120 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011121};
11122
Takashi Iwaice875f02008-01-28 18:17:43 +010011123/* update HP, line and mono-out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011124#define alc262_hp_master_update alc260_hp_master_update
Takashi Iwaice875f02008-01-28 18:17:43 +010011125
Takashi Iwaie9427962011-04-28 15:46:07 +020011126static void alc262_hp_bpc_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011127{
11128 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011129
Takashi Iwaie9427962011-04-28 15:46:07 +020011130 spec->autocfg.hp_pins[0] = 0x1b;
11131 spec->autocfg.speaker_pins[0] = 0x16;
11132 spec->automute = 1;
11133 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011134}
11135
Takashi Iwaie9427962011-04-28 15:46:07 +020011136static void alc262_hp_wildwest_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011137{
11138 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011139
Takashi Iwaie9427962011-04-28 15:46:07 +020011140 spec->autocfg.hp_pins[0] = 0x15;
11141 spec->autocfg.speaker_pins[0] = 0x16;
11142 spec->automute = 1;
11143 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011144}
11145
Takashi Iwaib72519b2009-05-08 14:31:55 +020011146#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011147#define alc262_hp_master_sw_put alc260_hp_master_sw_put
Takashi Iwaice875f02008-01-28 18:17:43 +010011148
Takashi Iwaib72519b2009-05-08 14:31:55 +020011149#define ALC262_HP_MASTER_SWITCH \
11150 { \
11151 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11152 .name = "Master Playback Switch", \
11153 .info = snd_ctl_boolean_mono_info, \
11154 .get = alc262_hp_master_sw_get, \
11155 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011156 }, \
11157 { \
11158 .iface = NID_MAPPING, \
11159 .name = "Master Playback Switch", \
11160 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011161 }
11162
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011163
Takashi Iwaia9111322011-05-02 11:30:18 +020011164static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011165 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011166 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11167 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11168 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011169 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11170 HDA_OUTPUT),
11171 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11172 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011173 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11174 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011175 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011176 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11177 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011178 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011179 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11180 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11181 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11182 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011183 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11184 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11185 { } /* end */
11186};
11187
Takashi Iwaia9111322011-05-02 11:30:18 +020011188static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011189 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011190 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11191 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11192 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11193 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011194 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11195 HDA_OUTPUT),
11196 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11197 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011198 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11199 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011200 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011201 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11202 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11203 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11204 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011205 { } /* end */
11206};
11207
Takashi Iwaia9111322011-05-02 11:30:18 +020011208static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010011209 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11210 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011211 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011212 { } /* end */
11213};
11214
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011215/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011216static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011217{
11218 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011219
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011220 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011221 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020011222 spec->automute = 1;
11223 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011224}
11225
Takashi Iwaia9111322011-05-02 11:30:18 +020011226static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011227 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11228 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011229 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11230 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11231 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11232 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011233 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011234 { } /* end */
11235};
11236
Takashi Iwaia9111322011-05-02 11:30:18 +020011237static const struct hda_verb alc262_hp_t5735_verbs[] = {
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011238 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11239 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11240
11241 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11242 { }
11243};
11244
Takashi Iwaia9111322011-05-02 11:30:18 +020011245static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011246 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11247 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011248 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11249 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011250 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11251 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11252 { } /* end */
11253};
11254
Takashi Iwaia9111322011-05-02 11:30:18 +020011255static const struct hda_verb alc262_hp_rp5700_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010011256 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11257 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11258 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11259 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11260 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11261 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11262 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11263 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11264 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11265 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11266 {}
11267};
11268
Takashi Iwaia9111322011-05-02 11:30:18 +020011269static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
Kailang Yang8c427222008-01-10 13:03:59 +010011270 .num_items = 1,
11271 .items = {
11272 { "Line", 0x1 },
11273 },
11274};
11275
Takashi Iwai42171c12009-05-08 14:11:43 +020011276/* bind hp and internal speaker mute (with plug check) as master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011277#define alc262_hippo_master_update alc262_hp_master_update
Takashi Iwai42171c12009-05-08 14:11:43 +020011278#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011279#define alc262_hippo_master_sw_put alc262_hp_master_sw_put
Takashi Iwai5b319542007-07-26 11:49:22 +020011280
Takashi Iwai42171c12009-05-08 14:11:43 +020011281#define ALC262_HIPPO_MASTER_SWITCH \
11282 { \
11283 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11284 .name = "Master Playback Switch", \
11285 .info = snd_ctl_boolean_mono_info, \
11286 .get = alc262_hippo_master_sw_get, \
11287 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011288 }, \
11289 { \
11290 .iface = NID_MAPPING, \
11291 .name = "Master Playback Switch", \
11292 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11293 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011294 }
11295
Takashi Iwaia9111322011-05-02 11:30:18 +020011296static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011297 ALC262_HIPPO_MASTER_SWITCH,
11298 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11299 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11300 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11301 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11302 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11303 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11304 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011305 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011306 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11307 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011308 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011309 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11310 { } /* end */
11311};
11312
Takashi Iwaia9111322011-05-02 11:30:18 +020011313static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011314 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11315 ALC262_HIPPO_MASTER_SWITCH,
11316 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11317 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11318 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11319 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11320 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11321 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011322 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011323 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11324 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011325 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011326 { } /* end */
11327};
11328
11329/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011330static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011331{
11332 struct alc_spec *spec = codec->spec;
11333
11334 spec->autocfg.hp_pins[0] = 0x15;
11335 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011336 spec->automute = 1;
11337 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011338}
11339
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011340static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011341{
11342 struct alc_spec *spec = codec->spec;
11343
11344 spec->autocfg.hp_pins[0] = 0x1b;
11345 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011346 spec->automute = 1;
11347 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011348}
11349
11350
Takashi Iwaia9111322011-05-02 11:30:18 +020011351static const struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011352 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011353 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011354 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11355 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11356 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11357 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11358 { } /* end */
11359};
11360
Takashi Iwaia9111322011-05-02 11:30:18 +020011361static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011362 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11363 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011364 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11365 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11366 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11367 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11368 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11369 { } /* end */
11370};
Kailang Yang272a5272007-05-14 11:00:38 +020011371
Takashi Iwaia9111322011-05-02 11:30:18 +020011372static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011373 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11374 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11375 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11376 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11377 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11378 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11379 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11380 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011381 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011382 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11383 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011384 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011385 { } /* end */
11386};
11387
Takashi Iwaia9111322011-05-02 11:30:18 +020011388static const struct hda_verb alc262_tyan_verbs[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011389 /* Headphone automute */
11390 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11391 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11392 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11393
11394 /* P11 AUX_IN, white 4-pin connector */
11395 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11396 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11397 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11398 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11399
11400 {}
11401};
11402
11403/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011404static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011405{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011406 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011407
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011408 spec->autocfg.hp_pins[0] = 0x1b;
11409 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +020011410 spec->automute = 1;
11411 spec->automute_mode = ALC_AUTOMUTE_AMP;
Tony Vroonba340e82009-02-02 19:01:30 +000011412}
11413
Tony Vroonba340e82009-02-02 19:01:30 +000011414
Kailang Yangdf694da2005-12-05 19:42:22 +010011415#define alc262_capture_mixer alc882_capture_mixer
11416#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11417
11418/*
11419 * generic initialization of ADC, input mixers and output mixers
11420 */
Takashi Iwaia9111322011-05-02 11:30:18 +020011421static const struct hda_verb alc262_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011422 /*
11423 * Unmute ADC0-2 and set the default input to mic-in
11424 */
11425 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11426 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11427 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11428 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11429 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11430 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11431
Takashi Iwaicb53c622007-08-10 17:21:45 +020011432 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011433 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011434 * Note: PASD motherboards uses the Line In 2 as the input for
11435 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011436 */
11437 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011438 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11439 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11440 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11441 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11442 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011443
11444 /*
11445 * Set up output mixers (0x0c - 0x0e)
11446 */
11447 /* set vol=0 to output mixers */
11448 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11449 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11450 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11451 /* set up input amps for analog loopback */
11452 /* Amp Indices: DAC = 0, mixer = 1 */
11453 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11454 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11455 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11456 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11457 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11458 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11459
11460 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11461 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11462 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11463 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11464 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11465 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11466
11467 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11468 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11469 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11470 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11471 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011472
Kailang Yangdf694da2005-12-05 19:42:22 +010011473 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11474 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011475
Kailang Yangdf694da2005-12-05 19:42:22 +010011476 /* FIXME: use matrix-type input source selection */
11477 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11478 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11479 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11480 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11481 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11482 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11483 /* Input mixer2 */
11484 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11485 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11486 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11487 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11488 /* Input mixer3 */
11489 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11490 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11491 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011492 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011493
11494 { }
11495};
11496
Takashi Iwaia9111322011-05-02 11:30:18 +020011497static const struct hda_verb alc262_eapd_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011498 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11499 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11500 { }
11501};
11502
Takashi Iwaia9111322011-05-02 11:30:18 +020011503static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +020011504 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11505 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11506 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11507
11508 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11509 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11510 {}
11511};
11512
Takashi Iwaia9111322011-05-02 11:30:18 +020011513static const struct hda_verb alc262_sony_unsol_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020011514 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11515 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11516 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11517
11518 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11519 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011520 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011521};
11522
Takashi Iwaia9111322011-05-02 11:30:18 +020011523static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011524 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11525 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11526 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11527 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11528 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011529 { } /* end */
11530};
11531
Takashi Iwaia9111322011-05-02 11:30:18 +020011532static const struct hda_verb alc262_toshiba_s06_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011533 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11534 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11535 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11536 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11537 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11538 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11539 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11540 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11541 {}
11542};
11543
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011544static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011545{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011546 struct alc_spec *spec = codec->spec;
11547
11548 spec->autocfg.hp_pins[0] = 0x15;
11549 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011550 spec->ext_mic.pin = 0x18;
11551 spec->ext_mic.mux_idx = 0;
11552 spec->int_mic.pin = 0x12;
11553 spec->int_mic.mux_idx = 9;
11554 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020011555 spec->automute = 1;
11556 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011557}
11558
Takashi Iwai834be882006-03-01 14:16:17 +010011559/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011560 * nec model
11561 * 0x15 = headphone
11562 * 0x16 = internal speaker
11563 * 0x18 = external mic
11564 */
11565
Takashi Iwaia9111322011-05-02 11:30:18 +020011566static const struct snd_kcontrol_new alc262_nec_mixer[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011567 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11568 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11569
11570 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11571 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011572 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011573
11574 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11575 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11576 { } /* end */
11577};
11578
Takashi Iwaia9111322011-05-02 11:30:18 +020011579static const struct hda_verb alc262_nec_verbs[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011580 /* Unmute Speaker */
11581 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11582
11583 /* Headphone */
11584 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11585 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11586
11587 /* External mic to headphone */
11588 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11589 /* External mic to speaker */
11590 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11591 {}
11592};
11593
11594/*
Takashi Iwai834be882006-03-01 14:16:17 +010011595 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011596 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11597 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011598 */
11599
Takashi Iwai20f5e0b2011-06-10 09:31:54 +020011600#define ALC_HP_EVENT ALC880_HP_EVENT
Takashi Iwai834be882006-03-01 14:16:17 +010011601
Takashi Iwaia9111322011-05-02 11:30:18 +020011602static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
Takashi Iwai834be882006-03-01 14:16:17 +010011603 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11604 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011605 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11606 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011607 {}
11608};
11609
Takashi Iwaia9111322011-05-02 11:30:18 +020011610static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011611 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11612 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11613 {}
11614};
11615
Takashi Iwaia9111322011-05-02 11:30:18 +020011616static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
Daniel T Chene2595322009-12-19 18:19:02 -050011617 /* Front Mic pin: input vref at 50% */
11618 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11619 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11620 {}
11621};
11622
Takashi Iwaia9111322011-05-02 11:30:18 +020011623static const struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011624 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011625 .items = {
11626 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011627 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011628 { "CD", 0x4 },
11629 },
11630};
11631
Takashi Iwaia9111322011-05-02 11:30:18 +020011632static const struct hda_input_mux alc262_HP_capture_source = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011633 .num_items = 5,
11634 .items = {
11635 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011636 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011637 { "Line", 0x2 },
11638 { "CD", 0x4 },
11639 { "AUX IN", 0x6 },
11640 },
11641};
11642
Takashi Iwaia9111322011-05-02 11:30:18 +020011643static const struct hda_input_mux alc262_HP_D7000_capture_source = {
zhejiangaccbe492007-08-31 12:36:05 +020011644 .num_items = 4,
11645 .items = {
11646 { "Mic", 0x0 },
11647 { "Front Mic", 0x2 },
11648 { "Line", 0x1 },
11649 { "CD", 0x4 },
11650 },
11651};
11652
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011653static void alc262_fujitsu_setup(struct hda_codec *codec)
Takashi Iwai834be882006-03-01 14:16:17 +010011654{
11655 struct alc_spec *spec = codec->spec;
Takashi Iwai834be882006-03-01 14:16:17 +010011656
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011657 spec->autocfg.hp_pins[0] = 0x14;
11658 spec->autocfg.hp_pins[1] = 0x1b;
11659 spec->autocfg.speaker_pins[0] = 0x15;
11660 spec->automute = 1;
11661 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011662}
11663
Takashi Iwai834be882006-03-01 14:16:17 +010011664/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaia9111322011-05-02 11:30:18 +020011665static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011666 .ops = &snd_hda_bind_vol,
11667 .values = {
11668 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11669 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11670 0
11671 },
11672};
Takashi Iwai834be882006-03-01 14:16:17 +010011673
Takashi Iwaia9111322011-05-02 11:30:18 +020011674static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011675 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011676 {
11677 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11678 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011679 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
11680 .info = snd_ctl_boolean_mono_info,
11681 .get = alc262_hp_master_sw_get,
11682 .put = alc262_hp_master_sw_put,
Takashi Iwai834be882006-03-01 14:16:17 +010011683 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011684 {
11685 .iface = NID_MAPPING,
11686 .name = "Master Playback Switch",
11687 .private_value = 0x1b,
11688 },
Takashi Iwai834be882006-03-01 14:16:17 +010011689 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),
Takashi Iwai834be882006-03-01 14:16:17 +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),
Takashi Iwai834be882006-03-01 14:16:17 +010011697 { } /* end */
11698};
11699
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011700static void alc262_lenovo_3000_setup(struct hda_codec *codec)
Jiang zhe0e31daf2008-03-20 12:12:39 +010011701{
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011702 struct alc_spec *spec = codec->spec;
Jiang zhe0e31daf2008-03-20 12:12:39 +010011703
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011704 spec->autocfg.hp_pins[0] = 0x1b;
11705 spec->autocfg.speaker_pins[0] = 0x14;
11706 spec->autocfg.speaker_pins[1] = 0x16;
11707 spec->automute = 1;
11708 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhe0e31daf2008-03-20 12:12:39 +010011709}
11710
Takashi Iwaia9111322011-05-02 11:30:18 +020011711static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011712 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11713 {
11714 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11715 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011716 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
11717 .info = snd_ctl_boolean_mono_info,
11718 .get = alc262_hp_master_sw_get,
11719 .put = alc262_hp_master_sw_put,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011720 },
11721 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11722 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011723 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011724 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11725 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011726 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011727 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11728 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011729 { } /* end */
11730};
11731
Takashi Iwaia9111322011-05-02 11:30:18 +020011732static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011733 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011734 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011735 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11736 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011737 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011738 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11739 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011740 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011741 { } /* end */
11742};
11743
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011744/* additional init verbs for Benq laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020011745static const struct hda_verb alc262_EAPD_verbs[] = {
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011746 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11747 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11748 {}
11749};
11750
Takashi Iwaia9111322011-05-02 11:30:18 +020011751static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
Kailang Yang83c34212007-07-05 11:43:05 +020011752 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11753 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11754
11755 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11756 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11757 {}
11758};
11759
Tobin Davisf651b502007-10-26 12:40:47 +020011760/* Samsung Q1 Ultra Vista model setup */
Takashi Iwaia9111322011-05-02 11:30:18 +020011761static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011762 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11763 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011764 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11765 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011766 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
11767 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011768 { } /* end */
11769};
11770
Takashi Iwaia9111322011-05-02 11:30:18 +020011771static const struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011772 /* output mixer */
11773 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11774 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11775 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11776 /* speaker */
11777 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11778 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11779 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11780 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11781 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011782 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011783 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11784 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11785 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11786 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11787 /* internal mic */
11788 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11789 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11790 /* ADC, choose mic */
11791 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11792 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11793 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11794 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11795 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11796 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11797 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11798 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11799 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11800 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011801 {}
11802};
11803
Tobin Davisf651b502007-10-26 12:40:47 +020011804/* mute/unmute internal speaker according to the hp jack and mute state */
11805static void alc262_ultra_automute(struct hda_codec *codec)
11806{
11807 struct alc_spec *spec = codec->spec;
11808 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011809
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011810 mute = 0;
11811 /* auto-mute only when HP is used as HP */
11812 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011813 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011814 if (spec->jack_present)
11815 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011816 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011817 /* mute/unmute internal speaker */
11818 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11819 HDA_AMP_MUTE, mute);
11820 /* mute/unmute HP */
11821 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11822 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011823}
11824
11825/* unsolicited event for HP jack sensing */
11826static void alc262_ultra_unsol_event(struct hda_codec *codec,
11827 unsigned int res)
11828{
11829 if ((res >> 26) != ALC880_HP_EVENT)
11830 return;
11831 alc262_ultra_automute(codec);
11832}
11833
Takashi Iwaia9111322011-05-02 11:30:18 +020011834static const struct hda_input_mux alc262_ultra_capture_source = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011835 .num_items = 2,
11836 .items = {
11837 { "Mic", 0x1 },
11838 { "Headphone", 0x7 },
11839 },
11840};
11841
11842static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11843 struct snd_ctl_elem_value *ucontrol)
11844{
11845 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11846 struct alc_spec *spec = codec->spec;
11847 int ret;
11848
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011849 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011850 if (!ret)
11851 return 0;
11852 /* reprogram the HP pin as mic or HP according to the input source */
11853 snd_hda_codec_write_cache(codec, 0x15, 0,
11854 AC_VERB_SET_PIN_WIDGET_CONTROL,
11855 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11856 alc262_ultra_automute(codec); /* mute/unmute HP */
11857 return ret;
11858}
11859
Takashi Iwaia9111322011-05-02 11:30:18 +020011860static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011861 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11862 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11863 {
11864 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11865 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011866 .info = alc_mux_enum_info,
11867 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011868 .put = alc262_ultra_mux_enum_put,
11869 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011870 {
11871 .iface = NID_MAPPING,
11872 .name = "Capture Source",
11873 .private_value = 0x15,
11874 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011875 { } /* end */
11876};
11877
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011878/* We use two mixers depending on the output pin; 0x16 is a mono output
11879 * and thus it's bound with a different mixer.
11880 * This function returns which mixer amp should be used.
11881 */
11882static int alc262_check_volbit(hda_nid_t nid)
11883{
11884 if (!nid)
11885 return 0;
11886 else if (nid == 0x16)
11887 return 2;
11888 else
11889 return 1;
11890}
11891
11892static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011893 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011894{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011895 unsigned long val;
11896 int vbit;
11897
11898 vbit = alc262_check_volbit(nid);
11899 if (!vbit)
11900 return 0;
11901 if (*vbits & vbit) /* a volume control for this mixer already there */
11902 return 0;
11903 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011904 if (vbit == 2)
11905 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11906 else
11907 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011908 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011909}
11910
11911static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011912 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011913{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011914 unsigned long val;
11915
11916 if (!nid)
11917 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011918 if (nid == 0x16)
11919 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11920 else
11921 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011922 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011923}
11924
Kailang Yangdf694da2005-12-05 19:42:22 +010011925/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011926static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11927 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011928{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011929 const char *pfx;
11930 int vbits;
Takashi Iwai6843ca12011-06-24 11:03:58 +020011931 int i, index, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011932
11933 spec->multiout.num_dacs = 1; /* only use one dac */
11934 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +020011935 spec->private_dac_nids[0] = 2;
Kailang Yangdf694da2005-12-05 19:42:22 +010011936
Takashi Iwai033688a2010-09-08 15:47:09 +020011937 for (i = 0; i < 2; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020011938 pfx = alc_get_line_out_pfx(spec, i, true, &index);
11939 if (!pfx)
11940 pfx = "PCM";
11941 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx,
11942 index);
Takashi Iwai033688a2010-09-08 15:47:09 +020011943 if (err < 0)
11944 return err;
11945 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
11946 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
11947 "Speaker", i);
11948 if (err < 0)
11949 return err;
11950 }
11951 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
11952 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
11953 "Headphone", i);
11954 if (err < 0)
11955 return err;
11956 }
11957 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011958
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011959 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11960 alc262_check_volbit(cfg->speaker_pins[0]) |
11961 alc262_check_volbit(cfg->hp_pins[0]);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011962 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020011963 for (i = 0; i < 2; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020011964 pfx = alc_get_line_out_pfx(spec, i, true, &index);
11965 if (!pfx)
11966 pfx = "PCM";
Takashi Iwai033688a2010-09-08 15:47:09 +020011967 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
11968 &vbits, i);
11969 if (err < 0)
11970 return err;
11971 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
11972 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
11973 "Speaker", &vbits, i);
11974 if (err < 0)
11975 return err;
11976 }
11977 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
11978 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
11979 "Headphone", &vbits, i);
11980 if (err < 0)
11981 return err;
11982 }
11983 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011984 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011985}
11986
Takashi Iwai05f5f472009-08-25 13:10:18 +020011987#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010011988 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010011989
Takashi Iwaia9111322011-05-02 11:30:18 +020011990static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011991 /*
11992 * Unmute ADC0-2 and set the default input to mic-in
11993 */
11994 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11995 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11996 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11997 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11998 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11999 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12000
Takashi Iwaicb53c622007-08-10 17:21:45 +020012001 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012002 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012003 * Note: PASD motherboards uses the Line In 2 as the input for
12004 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012005 */
12006 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012007 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12008 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12009 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12010 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12011 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12012 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12013 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012014
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012015 /*
12016 * Set up output mixers (0x0c - 0x0e)
12017 */
12018 /* set vol=0 to output mixers */
12019 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12020 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12021 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12022
12023 /* set up input amps for analog loopback */
12024 /* Amp Indices: DAC = 0, mixer = 1 */
12025 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12026 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12027 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12028 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12029 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12030 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12031
Takashi Iwaice875f02008-01-28 18:17:43 +010012032 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012033 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12034 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12035
12036 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12037 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12038
12039 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12040 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12041
12042 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12043 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12044 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12045 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12046 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12047
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012048 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012049 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12050 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012051 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012052 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12053 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12054
12055
12056 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012057 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12058 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012059 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012060 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12061 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12062 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12063 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12064 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12065 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12066 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12067 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012068 /* Input mixer2 */
12069 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012070 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12071 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12072 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12073 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12074 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12075 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12076 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12077 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012078 /* Input mixer3 */
12079 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012080 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12081 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12082 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12083 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12084 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12085 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12086 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12087 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012088
Takashi Iwaice875f02008-01-28 18:17:43 +010012089 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12090
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012091 { }
12092};
12093
Takashi Iwaia9111322011-05-02 11:30:18 +020012094static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010012095 /*
12096 * Unmute ADC0-2 and set the default input to mic-in
12097 */
12098 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12099 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12100 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12101 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12102 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12103 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12104
Takashi Iwaicb53c622007-08-10 17:21:45 +020012105 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012106 * mixer widget
12107 * Note: PASD motherboards uses the Line In 2 as the input for front
12108 * panel mic (mic 2)
12109 */
12110 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012111 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12112 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12113 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12114 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12115 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12116 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12117 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12118 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012119 /*
12120 * Set up output mixers (0x0c - 0x0e)
12121 */
12122 /* set vol=0 to output mixers */
12123 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12124 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12125 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12126
12127 /* set up input amps for analog loopback */
12128 /* Amp Indices: DAC = 0, mixer = 1 */
12129 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12130 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12131 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12132 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12133 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12134 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12135
12136
12137 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12138 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12139 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12140 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12141 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12142 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12143 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12144
12145 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12146 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12147
12148 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12149 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12150
12151 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12152 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12153 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12154 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12155 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12156 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12157
12158 /* FIXME: use matrix-type input source selection */
12159 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12160 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12161 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12162 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12163 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12164 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12165 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12166 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12167 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12168 /* Input mixer2 */
12169 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12170 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12171 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12172 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12173 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12174 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12175 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12176 /* Input mixer3 */
12177 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12178 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12179 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12180 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12181 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12182 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12183 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12184
Takashi Iwaice875f02008-01-28 18:17:43 +010012185 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12186
Kailang Yangcd7509a2007-01-26 18:33:17 +010012187 { }
12188};
12189
Takashi Iwaia9111322011-05-02 11:30:18 +020012190static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012191
12192 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12193 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12194 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12195
12196 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12197 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12198 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12199 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12200
12201 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12202 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12203 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12204 {}
12205};
12206
Takashi Iwai18675e42010-09-08 15:55:44 +020012207/*
12208 * Pin config fixes
12209 */
12210enum {
12211 PINFIX_FSC_H270,
David Henningssond2a19da2011-06-22 09:58:37 +020012212 PINFIX_HP_Z200,
Takashi Iwai18675e42010-09-08 15:55:44 +020012213};
12214
12215static const struct alc_fixup alc262_fixups[] = {
12216 [PINFIX_FSC_H270] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012217 .type = ALC_FIXUP_PINS,
12218 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai18675e42010-09-08 15:55:44 +020012219 { 0x14, 0x99130110 }, /* speaker */
12220 { 0x15, 0x0221142f }, /* front HP */
12221 { 0x1b, 0x0121141f }, /* rear HP */
12222 { }
12223 }
12224 },
David Henningssond2a19da2011-06-22 09:58:37 +020012225 [PINFIX_HP_Z200] = {
12226 .type = ALC_FIXUP_PINS,
12227 .v.pins = (const struct alc_pincfg[]) {
12228 { 0x16, 0x99130120 }, /* internal speaker */
12229 { }
12230 }
12231 },
Takashi Iwai18675e42010-09-08 15:55:44 +020012232};
12233
Takashi Iwaia9111322011-05-02 11:30:18 +020012234static const struct snd_pci_quirk alc262_fixup_tbl[] = {
David Henningssond2a19da2011-06-22 09:58:37 +020012235 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
Takashi Iwai18675e42010-09-08 15:55:44 +020012236 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12237 {}
12238};
12239
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012240
Takashi Iwaicb53c622007-08-10 17:21:45 +020012241#ifdef CONFIG_SND_HDA_POWER_SAVE
12242#define alc262_loopbacks alc880_loopbacks
12243#endif
12244
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012245/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012246#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12247#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12248#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12249#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12250
12251/*
12252 * BIOS auto configuration
12253 */
12254static int alc262_parse_auto_config(struct hda_codec *codec)
12255{
12256 struct alc_spec *spec = codec->spec;
12257 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012258 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012259
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012260 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12261 alc262_ignore);
12262 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012263 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012264 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012265 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012266 spec->multiout.max_channels = 2;
12267 spec->no_analog = 1;
12268 goto dig_only;
12269 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012270 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012271 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012272 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12273 if (err < 0)
12274 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012275 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012276 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012277 return err;
12278
12279 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12280
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012281 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012282 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012283
Takashi Iwai603c4012008-07-30 15:01:44 +020012284 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012285 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012286
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012287 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012288 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012289
Takashi Iwai776e1842007-08-29 15:07:11 +020012290 err = alc_auto_add_mic_boost(codec);
12291 if (err < 0)
12292 return err;
12293
Kailang Yang6227cdc2010-02-25 08:36:52 +010012294 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012295
Kailang Yangdf694da2005-12-05 19:42:22 +010012296 return 1;
12297}
12298
Kailang Yangdf694da2005-12-05 19:42:22 +010012299#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012300#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012301
12302
12303/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012304static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012305{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012306 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020012307 alc_auto_init_multi_out(codec);
12308 alc_auto_init_extra_out(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012309 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012310 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012311 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012312 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012313 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012314}
12315
12316/*
12317 * configuration and preset
12318 */
Takashi Iwaiea734962011-01-17 11:29:34 +010012319static const char * const alc262_models[ALC262_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012320 [ALC262_BASIC] = "basic",
12321 [ALC262_HIPPO] = "hippo",
12322 [ALC262_HIPPO_1] = "hippo_1",
12323 [ALC262_FUJITSU] = "fujitsu",
12324 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012325 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012326 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012327 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012328 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012329 [ALC262_BENQ_T31] = "benq-t31",
12330 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012331 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012332 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012333 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012334 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012335 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012336 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012337 [ALC262_AUTO] = "auto",
12338};
12339
Takashi Iwaia9111322011-05-02 11:30:18 +020012340static const struct snd_pci_quirk alc262_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012341 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012342 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012343 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12344 ALC262_HP_BPC),
12345 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12346 ALC262_HP_BPC),
Takashi Iwai5734a072011-01-19 17:07:12 +010012347 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
12348 ALC262_HP_BPC),
David Henningssond2a19da2011-06-22 09:58:37 +020012349 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
12350 ALC262_AUTO),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012351 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12352 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012353 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012354 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012355 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012356 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012357 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012358 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012359 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012360 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012361 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12362 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12363 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012364 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12365 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012366 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012367 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012368 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012369 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012370 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012371 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012372 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012373 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012374#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012375 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12376 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012377#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012378 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012379 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012380 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012381 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012382 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012383 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012384 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12385 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012386 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012387 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012388 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012389 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012390 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012391 {}
12392};
12393
Takashi Iwaia9111322011-05-02 11:30:18 +020012394static const struct alc_config_preset alc262_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010012395 [ALC262_BASIC] = {
12396 .mixers = { alc262_base_mixer },
12397 .init_verbs = { alc262_init_verbs },
12398 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12399 .dac_nids = alc262_dac_nids,
12400 .hp_nid = 0x03,
12401 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12402 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012403 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012404 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012405 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012406 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012407 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012408 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12409 .dac_nids = alc262_dac_nids,
12410 .hp_nid = 0x03,
12411 .dig_out_nid = ALC262_DIGOUT_NID,
12412 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12413 .channel_mode = alc262_modes,
12414 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012415 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012416 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012417 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012418 },
12419 [ALC262_HIPPO_1] = {
12420 .mixers = { alc262_hippo1_mixer },
12421 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12422 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12423 .dac_nids = alc262_dac_nids,
12424 .hp_nid = 0x02,
12425 .dig_out_nid = ALC262_DIGOUT_NID,
12426 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12427 .channel_mode = alc262_modes,
12428 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012429 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012430 .setup = alc262_hippo1_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012431 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012432 },
Takashi Iwai834be882006-03-01 14:16:17 +010012433 [ALC262_FUJITSU] = {
12434 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012435 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12436 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012437 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12438 .dac_nids = alc262_dac_nids,
12439 .hp_nid = 0x03,
12440 .dig_out_nid = ALC262_DIGOUT_NID,
12441 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12442 .channel_mode = alc262_modes,
12443 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012444 .unsol_event = alc_sku_unsol_event,
12445 .setup = alc262_fujitsu_setup,
12446 .init_hook = alc_inithook,
Takashi Iwai834be882006-03-01 14:16:17 +010012447 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012448 [ALC262_HP_BPC] = {
12449 .mixers = { alc262_HP_BPC_mixer },
12450 .init_verbs = { alc262_HP_BPC_init_verbs },
12451 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12452 .dac_nids = alc262_dac_nids,
12453 .hp_nid = 0x03,
12454 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12455 .channel_mode = alc262_modes,
12456 .input_mux = &alc262_HP_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012457 .unsol_event = alc_sku_unsol_event,
12458 .setup = alc262_hp_bpc_setup,
12459 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012460 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012461 [ALC262_HP_BPC_D7000_WF] = {
12462 .mixers = { alc262_HP_BPC_WildWest_mixer },
12463 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12464 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12465 .dac_nids = alc262_dac_nids,
12466 .hp_nid = 0x03,
12467 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12468 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012469 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012470 .unsol_event = alc_sku_unsol_event,
12471 .setup = alc262_hp_wildwest_setup,
12472 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012473 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012474 [ALC262_HP_BPC_D7000_WL] = {
12475 .mixers = { alc262_HP_BPC_WildWest_mixer,
12476 alc262_HP_BPC_WildWest_option_mixer },
12477 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12478 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12479 .dac_nids = alc262_dac_nids,
12480 .hp_nid = 0x03,
12481 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12482 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012483 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012484 .unsol_event = alc_sku_unsol_event,
12485 .setup = alc262_hp_wildwest_setup,
12486 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012487 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012488 [ALC262_HP_TC_T5735] = {
12489 .mixers = { alc262_hp_t5735_mixer },
12490 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12491 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12492 .dac_nids = alc262_dac_nids,
12493 .hp_nid = 0x03,
12494 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12495 .channel_mode = alc262_modes,
12496 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012497 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012498 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012499 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012500 },
12501 [ALC262_HP_RP5700] = {
12502 .mixers = { alc262_hp_rp5700_mixer },
12503 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12504 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12505 .dac_nids = alc262_dac_nids,
12506 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12507 .channel_mode = alc262_modes,
12508 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012509 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012510 [ALC262_BENQ_ED8] = {
12511 .mixers = { alc262_base_mixer },
12512 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12513 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12514 .dac_nids = alc262_dac_nids,
12515 .hp_nid = 0x03,
12516 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12517 .channel_mode = alc262_modes,
12518 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012519 },
Kailang Yang272a5272007-05-14 11:00:38 +020012520 [ALC262_SONY_ASSAMD] = {
12521 .mixers = { alc262_sony_mixer },
12522 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12523 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12524 .dac_nids = alc262_dac_nids,
12525 .hp_nid = 0x02,
12526 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12527 .channel_mode = alc262_modes,
12528 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012529 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012530 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012531 .init_hook = alc_inithook,
Kailang Yang83c34212007-07-05 11:43:05 +020012532 },
12533 [ALC262_BENQ_T31] = {
12534 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012535 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12536 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012537 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12538 .dac_nids = alc262_dac_nids,
12539 .hp_nid = 0x03,
12540 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12541 .channel_mode = alc262_modes,
12542 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012543 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012544 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012545 .init_hook = alc_inithook,
Kailang Yangea1fb292008-08-26 12:58:38 +020012546 },
Tobin Davisf651b502007-10-26 12:40:47 +020012547 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012548 .mixers = { alc262_ultra_mixer },
12549 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012550 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012551 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12552 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012553 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12554 .channel_mode = alc262_modes,
12555 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012556 .adc_nids = alc262_adc_nids, /* ADC0 */
12557 .capsrc_nids = alc262_capsrc_nids,
12558 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012559 .unsol_event = alc262_ultra_unsol_event,
12560 .init_hook = alc262_ultra_automute,
12561 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012562 [ALC262_LENOVO_3000] = {
12563 .mixers = { alc262_lenovo_3000_mixer },
12564 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012565 alc262_lenovo_3000_unsol_verbs,
12566 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012567 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12568 .dac_nids = alc262_dac_nids,
12569 .hp_nid = 0x03,
12570 .dig_out_nid = ALC262_DIGOUT_NID,
12571 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12572 .channel_mode = alc262_modes,
12573 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012574 .unsol_event = alc_sku_unsol_event,
12575 .setup = alc262_lenovo_3000_setup,
12576 .init_hook = alc_inithook,
Jiang zhe0e31daf2008-03-20 12:12:39 +010012577 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012578 [ALC262_NEC] = {
12579 .mixers = { alc262_nec_mixer },
12580 .init_verbs = { alc262_nec_verbs },
12581 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12582 .dac_nids = alc262_dac_nids,
12583 .hp_nid = 0x03,
12584 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12585 .channel_mode = alc262_modes,
12586 .input_mux = &alc262_capture_source,
12587 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012588 [ALC262_TOSHIBA_S06] = {
12589 .mixers = { alc262_toshiba_s06_mixer },
12590 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12591 alc262_eapd_verbs },
12592 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12593 .capsrc_nids = alc262_dmic_capsrc_nids,
12594 .dac_nids = alc262_dac_nids,
12595 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012596 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012597 .dig_out_nid = ALC262_DIGOUT_NID,
12598 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12599 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012600 .unsol_event = alc_sku_unsol_event,
12601 .setup = alc262_toshiba_s06_setup,
12602 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012603 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012604 [ALC262_TOSHIBA_RX1] = {
12605 .mixers = { alc262_toshiba_rx1_mixer },
12606 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12607 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12608 .dac_nids = alc262_dac_nids,
12609 .hp_nid = 0x03,
12610 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12611 .channel_mode = alc262_modes,
12612 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012613 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012614 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012615 .init_hook = alc_inithook,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012616 },
Tony Vroonba340e82009-02-02 19:01:30 +000012617 [ALC262_TYAN] = {
12618 .mixers = { alc262_tyan_mixer },
12619 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12620 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12621 .dac_nids = alc262_dac_nids,
12622 .hp_nid = 0x02,
12623 .dig_out_nid = ALC262_DIGOUT_NID,
12624 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12625 .channel_mode = alc262_modes,
12626 .input_mux = &alc262_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020012627 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012628 .setup = alc262_tyan_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020012629 .init_hook = alc_hp_automute,
Tony Vroonba340e82009-02-02 19:01:30 +000012630 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012631};
12632
12633static int patch_alc262(struct hda_codec *codec)
12634{
12635 struct alc_spec *spec;
12636 int board_config;
12637 int err;
12638
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012639 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012640 if (spec == NULL)
12641 return -ENOMEM;
12642
12643 codec->spec = spec;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020012644
12645 spec->mixer_nid = 0x0b;
12646
Kailang Yangdf694da2005-12-05 19:42:22 +010012647#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012648 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12649 * under-run
12650 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012651 {
12652 int tmp;
12653 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12654 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12655 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12656 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12657 }
12658#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012659 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012660
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012661 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12662
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012663 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12664 alc262_models,
12665 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012666
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012667 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012668 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12669 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012670 board_config = ALC262_AUTO;
12671 }
12672
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012673 if (board_config == ALC262_AUTO) {
12674 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
12675 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
12676 }
Takashi Iwai18675e42010-09-08 15:55:44 +020012677
Kailang Yangdf694da2005-12-05 19:42:22 +010012678 if (board_config == ALC262_AUTO) {
12679 /* automatic parse from the BIOS config */
12680 err = alc262_parse_auto_config(codec);
12681 if (err < 0) {
12682 alc_free(codec);
12683 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012684 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012685 printk(KERN_INFO
12686 "hda_codec: Cannot set up configuration "
12687 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012688 board_config = ALC262_BASIC;
12689 }
12690 }
12691
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012692 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012693 err = snd_hda_attach_beep_device(codec, 0x1);
12694 if (err < 0) {
12695 alc_free(codec);
12696 return err;
12697 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012698 }
12699
Kailang Yangdf694da2005-12-05 19:42:22 +010012700 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012701 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012702
Kailang Yangdf694da2005-12-05 19:42:22 +010012703 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12704 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012705
Kailang Yangdf694da2005-12-05 19:42:22 +010012706 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12707 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12708
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012709 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012710 int i;
12711 /* check whether the digital-mic has to be supported */
12712 for (i = 0; i < spec->input_mux->num_items; i++) {
12713 if (spec->input_mux->items[i].index >= 9)
12714 break;
12715 }
12716 if (i < spec->input_mux->num_items) {
12717 /* use only ADC0 */
12718 spec->adc_nids = alc262_dmic_adc_nids;
12719 spec->num_adc_nids = 1;
12720 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012721 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012722 /* all analog inputs */
12723 /* check whether NID 0x07 is valid */
12724 unsigned int wcap = get_wcaps(codec, 0x07);
12725
12726 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012727 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012728 if (wcap != AC_WID_AUD_IN) {
12729 spec->adc_nids = alc262_adc_nids_alt;
12730 spec->num_adc_nids =
12731 ARRAY_SIZE(alc262_adc_nids_alt);
12732 spec->capsrc_nids = alc262_capsrc_nids_alt;
12733 } else {
12734 spec->adc_nids = alc262_adc_nids;
12735 spec->num_adc_nids =
12736 ARRAY_SIZE(alc262_adc_nids);
12737 spec->capsrc_nids = alc262_capsrc_nids;
12738 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012739 }
12740 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012741 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012742 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012743 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012744 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012745
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012746 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai18675e42010-09-08 15:55:44 +020012747
Takashi Iwai2134ea42008-01-10 16:53:55 +010012748 spec->vmaster_nid = 0x0c;
12749
Kailang Yangdf694da2005-12-05 19:42:22 +010012750 codec->patch_ops = alc_patch_ops;
12751 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012752 spec->init_hook = alc262_auto_init;
Takashi Iwai1c7161532011-04-07 10:37:16 +020012753 spec->shutup = alc_eapd_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020012754
12755 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020012756#ifdef CONFIG_SND_HDA_POWER_SAVE
12757 if (!spec->loopback.amplist)
12758 spec->loopback.amplist = alc262_loopbacks;
12759#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012760
Kailang Yangdf694da2005-12-05 19:42:22 +010012761 return 0;
12762}
12763
Kailang Yangdf694da2005-12-05 19:42:22 +010012764/*
Kailang Yanga361d842007-06-05 12:30:55 +020012765 * ALC268 channel source setting (2 channel)
12766 */
12767#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12768#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012769
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012770static const hda_nid_t alc268_dac_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012771 /* front, hp */
12772 0x02, 0x03
12773};
12774
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012775static const hda_nid_t alc268_adc_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012776 /* ADC0-1 */
12777 0x08, 0x07
12778};
12779
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012780static const hda_nid_t alc268_adc_nids_alt[1] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012781 /* ADC0 */
12782 0x08
12783};
12784
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012785static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
Takashi Iwaie1406342008-02-11 18:32:32 +010012786
Takashi Iwaia9111322011-05-02 11:30:18 +020012787static const struct snd_kcontrol_new alc268_base_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012788 /* output mixer control */
12789 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12790 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12791 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12792 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012793 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12794 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
12795 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012796 { }
12797};
12798
Takashi Iwaia9111322011-05-02 11:30:18 +020012799static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012800 /* output mixer control */
12801 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12802 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12803 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010012804 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12805 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
12806 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020012807 { }
12808};
12809
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012810/* bind Beep switches of both NID 0x0f and 0x10 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012811static const struct hda_bind_ctls alc268_bind_beep_sw = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012812 .ops = &snd_hda_bind_sw,
12813 .values = {
12814 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12815 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12816 0
12817 },
12818};
12819
Takashi Iwaia9111322011-05-02 11:30:18 +020012820static const struct snd_kcontrol_new alc268_beep_mixer[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012821 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12822 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12823 { }
12824};
12825
Takashi Iwaia9111322011-05-02 11:30:18 +020012826static const struct hda_verb alc268_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020012827 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12828 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12829 { }
12830};
12831
Takashi Iwaid2738092007-08-16 14:59:45 +020012832/* Toshiba specific */
Takashi Iwaia9111322011-05-02 11:30:18 +020012833static const struct hda_verb alc268_toshiba_verbs[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020012834 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12835 { } /* end */
12836};
12837
12838/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012839/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012840static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
Takashi Iwai6bc96852007-08-17 09:02:12 +020012841 .ops = &snd_hda_bind_vol,
12842 .values = {
12843 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12844 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12845 0
12846 },
12847};
12848
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012849static void alc268_acer_setup(struct hda_codec *codec)
Takashi Iwai889c4392007-08-23 18:56:52 +020012850{
12851 struct alc_spec *spec = codec->spec;
Takashi Iwai889c4392007-08-23 18:56:52 +020012852
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012853 spec->autocfg.hp_pins[0] = 0x14;
12854 spec->autocfg.speaker_pins[0] = 0x15;
12855 spec->automute = 1;
12856 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai889c4392007-08-23 18:56:52 +020012857}
12858
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012859#define alc268_acer_master_sw_get alc262_hp_master_sw_get
12860#define alc268_acer_master_sw_put alc262_hp_master_sw_put
Takashi Iwaid2738092007-08-16 14:59:45 +020012861
Takashi Iwaia9111322011-05-02 11:30:18 +020012862static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020012863 /* output mixer control */
12864 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12865 {
12866 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12867 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012868 .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
12869 .info = snd_ctl_boolean_mono_info,
12870 .get = alc268_acer_master_sw_get,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012871 .put = alc268_acer_master_sw_put,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012872 },
12873 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12874 { }
12875};
12876
Takashi Iwaia9111322011-05-02 11:30:18 +020012877static const struct snd_kcontrol_new alc268_acer_mixer[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020012878 /* output mixer control */
12879 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12880 {
12881 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12882 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012883 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12884 .info = snd_ctl_boolean_mono_info,
12885 .get = alc268_acer_master_sw_get,
Takashi Iwaid2738092007-08-16 14:59:45 +020012886 .put = alc268_acer_master_sw_put,
Takashi Iwaid2738092007-08-16 14:59:45 +020012887 },
David Henningsson5f99f862011-01-04 15:24:24 +010012888 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12889 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
12890 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012891 { }
12892};
12893
Takashi Iwaia9111322011-05-02 11:30:18 +020012894static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012895 /* output mixer control */
12896 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12897 {
12898 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12899 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012900 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12901 .info = snd_ctl_boolean_mono_info,
12902 .get = alc268_acer_master_sw_get,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012903 .put = alc268_acer_master_sw_put,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012904 },
David Henningsson5f99f862011-01-04 15:24:24 +010012905 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12906 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012907 { }
12908};
12909
Takashi Iwaia9111322011-05-02 11:30:18 +020012910static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020012911 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12912 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12913 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12914 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12915 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12916 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12917 { }
12918};
12919
Takashi Iwaia9111322011-05-02 11:30:18 +020012920static const struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012921 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12922 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012923 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12924 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012925 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12926 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012927 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12928 { }
12929};
12930
12931/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012932#define alc268_toshiba_setup alc262_hippo_setup
Takashi Iwaid2738092007-08-16 14:59:45 +020012933
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012934static void alc268_acer_lc_setup(struct hda_codec *codec)
12935{
12936 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020012937 spec->autocfg.hp_pins[0] = 0x15;
12938 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020012939 spec->automute = 1;
Takashi Iwai54463a62011-06-13 08:32:06 +020012940 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012941 spec->ext_mic.pin = 0x18;
12942 spec->ext_mic.mux_idx = 0;
12943 spec->int_mic.pin = 0x12;
12944 spec->int_mic.mux_idx = 6;
12945 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012946}
12947
Takashi Iwaia9111322011-05-02 11:30:18 +020012948static const struct snd_kcontrol_new alc268_dell_mixer[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012949 /* output mixer control */
12950 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12951 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12952 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12953 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012954 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12955 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012956 { }
12957};
12958
Takashi Iwaia9111322011-05-02 11:30:18 +020012959static const struct hda_verb alc268_dell_verbs[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012960 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12961 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12962 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012963 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012964 { }
12965};
12966
12967/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012968static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012969{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012970 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012971
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012972 spec->autocfg.hp_pins[0] = 0x15;
12973 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012974 spec->ext_mic.pin = 0x18;
12975 spec->ext_mic.mux_idx = 0;
12976 spec->int_mic.pin = 0x19;
12977 spec->int_mic.mux_idx = 1;
12978 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020012979 spec->automute = 1;
12980 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012981}
12982
Takashi Iwaia9111322011-05-02 11:30:18 +020012983static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012984 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12985 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12986 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12987 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12988 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12989 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012990 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12991 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012992 { }
12993};
12994
Takashi Iwaia9111322011-05-02 11:30:18 +020012995static const struct hda_verb alc267_quanta_il1_verbs[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012996 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12997 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12998 { }
12999};
13000
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013001static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013002{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013003 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013004 spec->autocfg.hp_pins[0] = 0x15;
13005 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013006 spec->ext_mic.pin = 0x18;
13007 spec->ext_mic.mux_idx = 0;
13008 spec->int_mic.pin = 0x19;
13009 spec->int_mic.mux_idx = 1;
13010 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020013011 spec->automute = 1;
13012 spec->automute_mode = ALC_AUTOMUTE_PIN;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013013}
13014
Kailang Yanga361d842007-06-05 12:30:55 +020013015/*
13016 * generic initialization of ADC, input mixers and output mixers
13017 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013018static const struct hda_verb alc268_base_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013019 /* Unmute DAC0-1 and set vol = 0 */
13020 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013021 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013022
13023 /*
13024 * Set up output mixers (0x0c - 0x0e)
13025 */
13026 /* set vol=0 to output mixers */
13027 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013028 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13029
13030 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13031 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13032
13033 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13034 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13035 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13036 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13037 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13038 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13039 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13040 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13041
13042 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13043 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13044 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13045 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013046 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013047
13048 /* set PCBEEP vol = 0, mute connections */
13049 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13050 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13051 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013052
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013053 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013054
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013055 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13056 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13057 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13058 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013059
Kailang Yanga361d842007-06-05 12:30:55 +020013060 { }
13061};
13062
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013063/* only for model=test */
13064#ifdef CONFIG_SND_DEBUG
Kailang Yanga361d842007-06-05 12:30:55 +020013065/*
13066 * generic initialization of ADC, input mixers and output mixers
13067 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013068static const struct hda_verb alc268_volume_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013069 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013070 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13071 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013072
13073 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13074 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13075 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13076 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13077 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13078
Kailang Yanga361d842007-06-05 12:30:55 +020013079 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013080 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13081 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13082
13083 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013084 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013085 { }
13086};
13087#endif /* CONFIG_SND_DEBUG */
Kailang Yanga361d842007-06-05 12:30:55 +020013088
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013089/* set PCBEEP vol = 0, mute connections */
13090static const struct hda_verb alc268_beep_init_verbs[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013091 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13092 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13093 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013094 { }
13095};
13096
Takashi Iwaia9111322011-05-02 11:30:18 +020013097static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013098 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13099 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13100 { } /* end */
13101};
13102
Takashi Iwaia9111322011-05-02 11:30:18 +020013103static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013104 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13105 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013106 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013107 { } /* end */
13108};
13109
Takashi Iwaia9111322011-05-02 11:30:18 +020013110static const struct snd_kcontrol_new alc268_capture_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013111 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13112 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13113 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13114 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013115 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013116 { } /* end */
13117};
13118
Takashi Iwaia9111322011-05-02 11:30:18 +020013119static const struct hda_input_mux alc268_capture_source = {
Kailang Yanga361d842007-06-05 12:30:55 +020013120 .num_items = 4,
13121 .items = {
13122 { "Mic", 0x0 },
13123 { "Front Mic", 0x1 },
13124 { "Line", 0x2 },
13125 { "CD", 0x3 },
13126 },
13127};
13128
Takashi Iwaia9111322011-05-02 11:30:18 +020013129static const struct hda_input_mux alc268_acer_capture_source = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013130 .num_items = 3,
13131 .items = {
13132 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013133 { "Internal Mic", 0x1 },
13134 { "Line", 0x2 },
13135 },
13136};
13137
Takashi Iwaia9111322011-05-02 11:30:18 +020013138static const struct hda_input_mux alc268_acer_dmic_capture_source = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013139 .num_items = 3,
13140 .items = {
13141 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013142 { "Internal Mic", 0x6 },
13143 { "Line", 0x2 },
13144 },
13145};
13146
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013147#ifdef CONFIG_SND_DEBUG
Takashi Iwaia9111322011-05-02 11:30:18 +020013148static const struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013149 /* Volume widgets */
13150 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13151 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13152 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13153 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13154 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13155 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13156 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13157 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13158 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13159 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13160 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13161 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13162 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013163 /* The below appears problematic on some hardwares */
13164 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013165 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13166 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13167 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13168 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13169
13170 /* Modes for retasking pin widgets */
13171 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13172 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13173 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13174 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13175
13176 /* Controls for GPIO pins, assuming they are configured as outputs */
13177 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13178 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13179 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13180 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13181
13182 /* Switches to allow the digital SPDIF output pin to be enabled.
13183 * The ALC268 does not have an SPDIF input.
13184 */
13185 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13186
13187 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13188 * this output to turn on an external amplifier.
13189 */
13190 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13191 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13192
13193 { } /* end */
13194};
13195#endif
13196
Kailang Yanga361d842007-06-05 12:30:55 +020013197/* create input playback/capture controls for the given pin */
13198static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13199 const char *ctlname, int idx)
13200{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013201 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013202 int err;
13203
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013204 switch (nid) {
13205 case 0x14:
13206 case 0x16:
13207 dac = 0x02;
13208 break;
13209 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013210 case 0x1a: /* ALC259/269 only */
13211 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013212 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013213 dac = 0x03;
13214 break;
13215 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013216 snd_printd(KERN_WARNING "hda_codec: "
13217 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013218 return 0;
13219 }
13220 if (spec->multiout.dac_nids[0] != dac &&
13221 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013222 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013223 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013224 HDA_OUTPUT));
13225 if (err < 0)
13226 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020013227 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013228 }
13229
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013230 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013231 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013232 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013233 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013234 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013235 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013236 if (err < 0)
13237 return err;
13238 return 0;
13239}
13240
13241/* add playback controls from the parsed DAC table */
13242static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13243 const struct auto_pin_cfg *cfg)
13244{
13245 hda_nid_t nid;
13246 int err;
13247
Kailang Yanga361d842007-06-05 12:30:55 +020013248 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013249
13250 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013251 if (nid) {
13252 const char *name;
Takashi Iwai2e925dd2011-06-24 11:27:22 +020013253 int index;
13254 name = alc_get_line_out_pfx(spec, 0, true, &index);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013255 err = alc268_new_analog_output(spec, nid, name, 0);
13256 if (err < 0)
13257 return err;
13258 }
Kailang Yanga361d842007-06-05 12:30:55 +020013259
13260 nid = cfg->speaker_pins[0];
13261 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013262 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013263 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13264 if (err < 0)
13265 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013266 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013267 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13268 if (err < 0)
13269 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013270 }
13271 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013272 if (nid) {
13273 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13274 if (err < 0)
13275 return err;
13276 }
Kailang Yanga361d842007-06-05 12:30:55 +020013277
13278 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13279 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013280 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013281 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013282 if (err < 0)
13283 return err;
13284 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013285 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013286}
13287
13288/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013289static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013290 const struct auto_pin_cfg *cfg)
13291{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013292 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013293}
13294
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013295static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13296 hda_nid_t nid, int pin_type)
13297{
13298 int idx;
13299
13300 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai4f574b72011-06-27 16:17:07 +020013301 if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
13302 return;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013303 if (nid == 0x14 || nid == 0x16)
13304 idx = 0;
13305 else
13306 idx = 1;
13307 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13308}
13309
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013310static void alc268_auto_init_dac(struct hda_codec *codec, hda_nid_t nid)
13311{
13312 if (!nid)
13313 return;
13314 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020013315 AMP_OUT_ZERO);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013316}
13317
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013318static void alc268_auto_init_multi_out(struct hda_codec *codec)
13319{
13320 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013321 int i;
13322
13323 for (i = 0; i < spec->autocfg.line_outs; i++) {
13324 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013325 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13326 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13327 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013328 /* mute DACs */
13329 for (i = 0; i < spec->multiout.num_dacs; i++)
13330 alc268_auto_init_dac(codec, spec->multiout.dac_nids[i]);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013331}
13332
13333static void alc268_auto_init_hp_out(struct hda_codec *codec)
13334{
13335 struct alc_spec *spec = codec->spec;
13336 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013337 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013338
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013339 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13340 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013341 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013342 }
13343 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13344 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013345 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013346 }
13347 if (spec->autocfg.mono_out_pin)
13348 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13349 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013350 /* mute DACs */
13351 alc268_auto_init_dac(codec, spec->multiout.hp_nid);
13352 for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
13353 alc268_auto_init_dac(codec, spec->multiout.extra_out_nid[i]);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013354}
13355
Kailang Yanga361d842007-06-05 12:30:55 +020013356static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13357{
13358 struct alc_spec *spec = codec->spec;
13359 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13360 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13361 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13362 unsigned int dac_vol1, dac_vol2;
13363
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013364 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013365 snd_hda_codec_write(codec, speaker_nid, 0,
13366 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013367 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013368 snd_hda_codec_write(codec, 0x0f, 0,
13369 AC_VERB_SET_AMP_GAIN_MUTE,
13370 AMP_IN_UNMUTE(1));
13371 snd_hda_codec_write(codec, 0x10, 0,
13372 AC_VERB_SET_AMP_GAIN_MUTE,
13373 AMP_IN_UNMUTE(1));
13374 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013375 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013376 snd_hda_codec_write(codec, 0x0f, 0,
13377 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13378 snd_hda_codec_write(codec, 0x10, 0,
13379 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13380 }
13381
13382 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013383 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013384 dac_vol2 = AMP_OUT_ZERO;
13385 else if (line_nid == 0x15)
13386 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013387 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013388 dac_vol2 = AMP_OUT_ZERO;
13389 else if (hp_nid == 0x15)
13390 dac_vol1 = AMP_OUT_ZERO;
13391 if (line_nid != 0x16 || hp_nid != 0x16 ||
13392 spec->autocfg.line_out_pins[1] != 0x16 ||
13393 spec->autocfg.line_out_pins[2] != 0x16)
13394 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13395
13396 snd_hda_codec_write(codec, 0x02, 0,
13397 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13398 snd_hda_codec_write(codec, 0x03, 0,
13399 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13400}
13401
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013402/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013403#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13404#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013405#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013406#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13407
13408/*
13409 * BIOS auto configuration
13410 */
13411static int alc268_parse_auto_config(struct hda_codec *codec)
13412{
13413 struct alc_spec *spec = codec->spec;
13414 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013415 static const hda_nid_t alc268_ignore[] = { 0 };
Kailang Yanga361d842007-06-05 12:30:55 +020013416
13417 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13418 alc268_ignore);
13419 if (err < 0)
13420 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013421 if (!spec->autocfg.line_outs) {
13422 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13423 spec->multiout.max_channels = 2;
13424 spec->no_analog = 1;
13425 goto dig_only;
13426 }
Kailang Yanga361d842007-06-05 12:30:55 +020013427 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013428 }
Kailang Yanga361d842007-06-05 12:30:55 +020013429 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13430 if (err < 0)
13431 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013432 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013433 if (err < 0)
13434 return err;
13435
13436 spec->multiout.max_channels = 2;
13437
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013438 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013439 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013440 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013441 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013442 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013443
Takashi Iwai4f574b72011-06-27 16:17:07 +020013444 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
Takashi Iwaid88897e2008-10-31 15:01:37 +010013445 add_mixer(spec, alc268_beep_mixer);
Takashi Iwai4f574b72011-06-27 16:17:07 +020013446 add_verb(spec, alc268_beep_init_verbs);
13447 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013448
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013449 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013450 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013451
Takashi Iwai776e1842007-08-29 15:07:11 +020013452 err = alc_auto_add_mic_boost(codec);
13453 if (err < 0)
13454 return err;
13455
Kailang Yang6227cdc2010-02-25 08:36:52 +010013456 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013457
Kailang Yanga361d842007-06-05 12:30:55 +020013458 return 1;
13459}
13460
Kailang Yanga361d842007-06-05 12:30:55 +020013461#define alc268_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010013462#define alc268_auto_init_input_src alc882_auto_init_input_src
Kailang Yanga361d842007-06-05 12:30:55 +020013463
13464/* init callback for auto-configuration model -- overriding the default init */
13465static void alc268_auto_init(struct hda_codec *codec)
13466{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013467 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013468 alc268_auto_init_multi_out(codec);
13469 alc268_auto_init_hp_out(codec);
13470 alc268_auto_init_mono_speaker_out(codec);
13471 alc268_auto_init_analog_input(codec);
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010013472 alc268_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013473 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013474 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013475 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013476}
13477
13478/*
13479 * configuration and preset
13480 */
Takashi Iwaiea734962011-01-17 11:29:34 +010013481static const char * const alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013482 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013483 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013484 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013485 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013486 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013487 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013488 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013489 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013490#ifdef CONFIG_SND_DEBUG
13491 [ALC268_TEST] = "test",
13492#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013493 [ALC268_AUTO] = "auto",
13494};
13495
Takashi Iwaia9111322011-05-02 11:30:18 +020013496static const struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013497 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013498 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013499 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013500 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013501 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013502 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13503 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013504 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chen0a1896b2011-06-06 18:55:34 -040013505 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013506 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13507 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013508 /* almost compatible with toshiba but with optional digital outs;
13509 * auto-probing seems working fine
13510 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013511 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013512 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013513 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013514 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013515 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013516 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013517 {}
13518};
13519
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013520/* Toshiba laptops have no unique PCI SSID but only codec SSID */
Takashi Iwaia9111322011-05-02 11:30:18 +020013521static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013522 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13523 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13524 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13525 ALC268_TOSHIBA),
13526 {}
13527};
13528
Takashi Iwaia9111322011-05-02 11:30:18 +020013529static const struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013530 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013531 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13532 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013533 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13534 alc267_quanta_il1_verbs },
13535 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13536 .dac_nids = alc268_dac_nids,
13537 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13538 .adc_nids = alc268_adc_nids_alt,
13539 .hp_nid = 0x03,
13540 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13541 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013542 .unsol_event = alc_sku_unsol_event,
13543 .setup = alc267_quanta_il1_setup,
13544 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013545 },
Kailang Yanga361d842007-06-05 12:30:55 +020013546 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013547 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13548 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013549 .init_verbs = { alc268_base_init_verbs },
13550 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13551 .dac_nids = alc268_dac_nids,
13552 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13553 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013554 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013555 .hp_nid = 0x03,
13556 .dig_out_nid = ALC268_DIGOUT_NID,
13557 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13558 .channel_mode = alc268_modes,
13559 .input_mux = &alc268_capture_source,
13560 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013561 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013562 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013563 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013564 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13565 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013566 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13567 .dac_nids = alc268_dac_nids,
13568 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13569 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013570 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013571 .hp_nid = 0x03,
13572 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13573 .channel_mode = alc268_modes,
13574 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013575 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013576 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013577 .init_hook = alc_inithook,
Takashi Iwaid2738092007-08-16 14:59:45 +020013578 },
13579 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013580 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013581 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013582 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13583 alc268_acer_verbs },
13584 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13585 .dac_nids = alc268_dac_nids,
13586 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13587 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013588 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013589 .hp_nid = 0x02,
13590 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13591 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013592 .input_mux = &alc268_acer_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013593 .unsol_event = alc_sku_unsol_event,
13594 .setup = alc268_acer_setup,
13595 .init_hook = alc_inithook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013596 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013597 [ALC268_ACER_DMIC] = {
13598 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13599 alc268_beep_mixer },
13600 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13601 alc268_acer_verbs },
13602 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13603 .dac_nids = alc268_dac_nids,
13604 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13605 .adc_nids = alc268_adc_nids_alt,
13606 .capsrc_nids = alc268_capsrc_nids,
13607 .hp_nid = 0x02,
13608 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13609 .channel_mode = alc268_modes,
13610 .input_mux = &alc268_acer_dmic_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013611 .unsol_event = alc_sku_unsol_event,
13612 .setup = alc268_acer_setup,
13613 .init_hook = alc_inithook,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013614 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013615 [ALC268_ACER_ASPIRE_ONE] = {
13616 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013617 alc268_beep_mixer,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013618 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013619 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13620 alc268_acer_aspire_one_verbs },
13621 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13622 .dac_nids = alc268_dac_nids,
13623 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13624 .adc_nids = alc268_adc_nids_alt,
13625 .capsrc_nids = alc268_capsrc_nids,
13626 .hp_nid = 0x03,
13627 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13628 .channel_mode = alc268_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013629 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013630 .setup = alc268_acer_lc_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013631 .init_hook = alc_inithook,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013632 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013633 [ALC268_DELL] = {
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013634 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13635 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013636 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13637 alc268_dell_verbs },
13638 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13639 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013640 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13641 .adc_nids = alc268_adc_nids_alt,
13642 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013643 .hp_nid = 0x02,
13644 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13645 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013646 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013647 .setup = alc268_dell_setup,
13648 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013649 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013650 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013651 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13652 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013653 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13654 alc268_toshiba_verbs },
13655 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13656 .dac_nids = alc268_dac_nids,
13657 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13658 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013659 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013660 .hp_nid = 0x03,
13661 .dig_out_nid = ALC268_DIGOUT_NID,
13662 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13663 .channel_mode = alc268_modes,
13664 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013665 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013666 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013667 .init_hook = alc_inithook,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013668 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013669#ifdef CONFIG_SND_DEBUG
13670 [ALC268_TEST] = {
13671 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13672 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013673 alc268_volume_init_verbs,
13674 alc268_beep_init_verbs },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013675 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13676 .dac_nids = alc268_dac_nids,
13677 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13678 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013679 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013680 .hp_nid = 0x03,
13681 .dig_out_nid = ALC268_DIGOUT_NID,
13682 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13683 .channel_mode = alc268_modes,
13684 .input_mux = &alc268_capture_source,
13685 },
13686#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013687};
13688
13689static int patch_alc268(struct hda_codec *codec)
13690{
13691 struct alc_spec *spec;
13692 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013693 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013694
Julia Lawallef86f582009-12-19 08:18:03 +010013695 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013696 if (spec == NULL)
13697 return -ENOMEM;
13698
13699 codec->spec = spec;
13700
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013701 /* ALC268 has no aa-loopback mixer */
13702
Kailang Yanga361d842007-06-05 12:30:55 +020013703 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13704 alc268_models,
13705 alc268_cfg_tbl);
13706
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013707 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13708 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013709 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013710
Kailang Yanga361d842007-06-05 12:30:55 +020013711 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013712 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13713 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013714 board_config = ALC268_AUTO;
13715 }
13716
13717 if (board_config == ALC268_AUTO) {
13718 /* automatic parse from the BIOS config */
13719 err = alc268_parse_auto_config(codec);
13720 if (err < 0) {
13721 alc_free(codec);
13722 return err;
13723 } else if (!err) {
13724 printk(KERN_INFO
13725 "hda_codec: Cannot set up configuration "
13726 "from BIOS. Using base mode...\n");
13727 board_config = ALC268_3ST;
13728 }
13729 }
13730
13731 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013732 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013733
Kailang Yanga361d842007-06-05 12:30:55 +020013734 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13735 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013736 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013737
Kailang Yanga361d842007-06-05 12:30:55 +020013738 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13739
Takashi Iwai22971e32009-02-10 11:56:44 +010013740 has_beep = 0;
13741 for (i = 0; i < spec->num_mixers; i++) {
13742 if (spec->mixers[i] == alc268_beep_mixer) {
13743 has_beep = 1;
13744 break;
13745 }
13746 }
13747
13748 if (has_beep) {
13749 err = snd_hda_attach_beep_device(codec, 0x1);
13750 if (err < 0) {
13751 alc_free(codec);
13752 return err;
13753 }
13754 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13755 /* override the amp caps for beep generator */
13756 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013757 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13758 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13759 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13760 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013761 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013762
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013763 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013764 /* check whether NID 0x07 is valid */
13765 unsigned int wcap = get_wcaps(codec, 0x07);
Kailang Yanga361d842007-06-05 12:30:55 +020013766
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013767 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013768 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013769 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013770 if (spec->auto_mic ||
13771 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013772 spec->adc_nids = alc268_adc_nids_alt;
13773 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020013774 if (spec->auto_mic)
13775 fixup_automic_adc(codec);
Takashi Iwaifdbc66262009-08-19 00:18:10 +020013776 if (spec->auto_mic || spec->input_mux->num_items == 1)
13777 add_mixer(spec, alc268_capture_nosrc_mixer);
13778 else
13779 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013780 } else {
13781 spec->adc_nids = alc268_adc_nids;
13782 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010013783 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020013784 }
13785 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013786
13787 spec->vmaster_nid = 0x02;
13788
Kailang Yanga361d842007-06-05 12:30:55 +020013789 codec->patch_ops = alc_patch_ops;
13790 if (board_config == ALC268_AUTO)
13791 spec->init_hook = alc268_auto_init;
Takashi Iwai1c7161532011-04-07 10:37:16 +020013792 spec->shutup = alc_eapd_shutup;
Kailang Yangea1fb292008-08-26 12:58:38 +020013793
Kailang Yangbf1b0222010-10-21 08:49:56 +020013794 alc_init_jacks(codec);
13795
Kailang Yanga361d842007-06-05 12:30:55 +020013796 return 0;
13797}
13798
13799/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013800 * ALC269 channel source setting (2 channel)
13801 */
13802#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13803
13804#define alc269_dac_nids alc260_dac_nids
13805
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013806static const hda_nid_t alc269_adc_nids[1] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010013807 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013808 0x08,
13809};
13810
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013811static const hda_nid_t alc269_capsrc_nids[1] = {
Takashi Iwaie01bf502008-08-21 16:25:07 +020013812 0x23,
13813};
13814
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013815static const hda_nid_t alc269vb_adc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013816 /* ADC1 */
13817 0x09,
13818};
13819
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013820static const hda_nid_t alc269vb_capsrc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013821 0x22,
13822};
13823
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013824static const hda_nid_t alc269_adc_candidates[] = {
David Henningsson262ac222011-04-07 11:43:00 +020013825 0x08, 0x09, 0x07, 0x11,
Takashi Iwai66946352010-03-29 17:21:45 +020013826};
Takashi Iwaie01bf502008-08-21 16:25:07 +020013827
Kailang Yangf6a92242007-12-13 16:52:54 +010013828#define alc269_modes alc260_modes
13829#define alc269_capture_source alc880_lg_lw_capture_source
13830
Takashi Iwaia9111322011-05-02 11:30:18 +020013831static const struct snd_kcontrol_new alc269_base_mixer[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010013832 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13833 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13834 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13835 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13836 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13837 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013838 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010013839 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13840 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013841 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010013842 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13843 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13844 { } /* end */
13845};
13846
Takashi Iwaia9111322011-05-02 11:30:18 +020013847static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013848 /* output mixer control */
13849 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13850 {
13851 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13852 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013853 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013854 .info = snd_hda_mixer_amp_switch_info,
13855 .get = snd_hda_mixer_amp_switch_get,
13856 .put = alc268_acer_master_sw_put,
13857 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13858 },
13859 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13860 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013861 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013862 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13863 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013864 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013865 { }
13866};
13867
Takashi Iwaia9111322011-05-02 11:30:18 +020013868static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
Tony Vroon64154832008-11-06 15:08:49 +000013869 /* output mixer control */
13870 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13871 {
13872 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13873 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013874 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013875 .info = snd_hda_mixer_amp_switch_info,
13876 .get = snd_hda_mixer_amp_switch_get,
13877 .put = alc268_acer_master_sw_put,
13878 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13879 },
13880 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13881 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013882 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013883 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13884 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013885 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013886 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13887 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013888 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013889 { }
13890};
13891
Takashi Iwaia9111322011-05-02 11:30:18 +020013892static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013893 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013894 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013895 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013896 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013897 { } /* end */
13898};
13899
Takashi Iwaia9111322011-05-02 11:30:18 +020013900static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013901 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13902 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13903 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13904 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13905 { } /* end */
13906};
13907
Takashi Iwaia9111322011-05-02 11:30:18 +020013908static const struct snd_kcontrol_new alc269_asus_mixer[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020013909 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13910 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
13911 { } /* end */
13912};
13913
Kailang Yangf6a92242007-12-13 16:52:54 +010013914/* capture mixer elements */
Takashi Iwaia9111322011-05-02 11:30:18 +020013915static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013916 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13917 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013918 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13919 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013920 { } /* end */
13921};
13922
Takashi Iwaia9111322011-05-02 11:30:18 +020013923static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013924 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13925 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013926 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013927 { } /* end */
13928};
13929
Takashi Iwaia9111322011-05-02 11:30:18 +020013930static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013931 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13932 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013933 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13934 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013935 { } /* end */
13936};
13937
Takashi Iwaia9111322011-05-02 11:30:18 +020013938static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013939 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13940 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013941 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013942 { } /* end */
13943};
13944
Takashi Iwai26f5df22008-11-03 17:39:46 +010013945/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013946#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013947
Takashi Iwaia9111322011-05-02 11:30:18 +020013948static const struct hda_verb alc269_quanta_fl1_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013949 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13950 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13951 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13952 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13953 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13954 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13955 { }
13956};
13957
Takashi Iwaia9111322011-05-02 11:30:18 +020013958static const struct hda_verb alc269_lifebook_verbs[] = {
Tony Vroon64154832008-11-06 15:08:49 +000013959 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13960 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13961 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13962 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13963 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13964 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13965 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13966 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13967 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13968 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13969 { }
13970};
13971
Kailang Yang60db6b52008-08-26 13:13:00 +020013972/* toggle speaker-output according to the hp-jack state */
13973static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13974{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013975 alc_hp_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013976
13977 snd_hda_codec_write(codec, 0x20, 0,
13978 AC_VERB_SET_COEF_INDEX, 0x0c);
13979 snd_hda_codec_write(codec, 0x20, 0,
13980 AC_VERB_SET_PROC_COEF, 0x680);
13981
13982 snd_hda_codec_write(codec, 0x20, 0,
13983 AC_VERB_SET_COEF_INDEX, 0x0c);
13984 snd_hda_codec_write(codec, 0x20, 0,
13985 AC_VERB_SET_PROC_COEF, 0x480);
13986}
13987
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013988#define alc269_lifebook_speaker_automute \
13989 alc269_quanta_fl1_speaker_automute
Tony Vroon64154832008-11-06 15:08:49 +000013990
Tony Vroon64154832008-11-06 15:08:49 +000013991static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13992{
13993 unsigned int present_laptop;
13994 unsigned int present_dock;
13995
Wu Fengguang864f92b2009-11-18 12:38:02 +080013996 present_laptop = snd_hda_jack_detect(codec, 0x18);
13997 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013998
13999 /* Laptop mic port overrides dock mic port, design decision */
14000 if (present_dock)
14001 snd_hda_codec_write(codec, 0x23, 0,
14002 AC_VERB_SET_CONNECT_SEL, 0x3);
14003 if (present_laptop)
14004 snd_hda_codec_write(codec, 0x23, 0,
14005 AC_VERB_SET_CONNECT_SEL, 0x0);
14006 if (!present_dock && !present_laptop)
14007 snd_hda_codec_write(codec, 0x23, 0,
14008 AC_VERB_SET_CONNECT_SEL, 0x1);
14009}
14010
Kailang Yang60db6b52008-08-26 13:13:00 +020014011static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14012 unsigned int res)
14013{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014014 switch (res >> 26) {
14015 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014016 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014017 break;
14018 case ALC880_MIC_EVENT:
14019 alc_mic_automute(codec);
14020 break;
14021 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014022}
14023
Tony Vroon64154832008-11-06 15:08:49 +000014024static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14025 unsigned int res)
14026{
14027 if ((res >> 26) == ALC880_HP_EVENT)
14028 alc269_lifebook_speaker_automute(codec);
14029 if ((res >> 26) == ALC880_MIC_EVENT)
14030 alc269_lifebook_mic_autoswitch(codec);
14031}
14032
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014033static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14034{
14035 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014036 spec->autocfg.hp_pins[0] = 0x15;
14037 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014038 spec->automute_mixer_nid[0] = 0x0c;
14039 spec->automute = 1;
14040 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014041 spec->ext_mic.pin = 0x18;
14042 spec->ext_mic.mux_idx = 0;
14043 spec->int_mic.pin = 0x19;
14044 spec->int_mic.mux_idx = 1;
14045 spec->auto_mic = 1;
14046}
14047
Kailang Yang60db6b52008-08-26 13:13:00 +020014048static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14049{
14050 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014051 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014052}
14053
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014054static void alc269_lifebook_setup(struct hda_codec *codec)
14055{
14056 struct alc_spec *spec = codec->spec;
14057 spec->autocfg.hp_pins[0] = 0x15;
14058 spec->autocfg.hp_pins[1] = 0x1a;
14059 spec->autocfg.speaker_pins[0] = 0x14;
14060 spec->automute_mixer_nid[0] = 0x0c;
14061 spec->automute = 1;
14062 spec->automute_mode = ALC_AUTOMUTE_MIXER;
14063}
14064
Tony Vroon64154832008-11-06 15:08:49 +000014065static void alc269_lifebook_init_hook(struct hda_codec *codec)
14066{
14067 alc269_lifebook_speaker_automute(codec);
14068 alc269_lifebook_mic_autoswitch(codec);
14069}
14070
Takashi Iwaia9111322011-05-02 11:30:18 +020014071static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014072 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14073 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14074 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14075 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14076 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14077 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14078 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14079 {}
14080};
14081
Takashi Iwaia9111322011-05-02 11:30:18 +020014082static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014083 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14084 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14085 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14086 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14087 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14088 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14089 {}
14090};
14091
Takashi Iwaia9111322011-05-02 11:30:18 +020014092static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014093 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14094 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14095 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14096 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14097 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14098 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14099 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14100 {}
14101};
14102
Takashi Iwaia9111322011-05-02 11:30:18 +020014103static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014104 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14105 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14106 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14107 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14108 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14109 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14110 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14111 {}
14112};
14113
Takashi Iwaia9111322011-05-02 11:30:18 +020014114static const struct hda_verb alc271_acer_dmic_verbs[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014115 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14116 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14117 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14118 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14119 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14120 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14121 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14122 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14123 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14124 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14125 { }
14126};
14127
Kailang Yang226b1ec2010-04-09 11:01:20 +020014128static void alc269_laptop_amic_setup(struct hda_codec *codec)
14129{
14130 struct alc_spec *spec = codec->spec;
14131 spec->autocfg.hp_pins[0] = 0x15;
14132 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014133 spec->automute_mixer_nid[0] = 0x0c;
14134 spec->automute = 1;
14135 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014136 spec->ext_mic.pin = 0x18;
14137 spec->ext_mic.mux_idx = 0;
14138 spec->int_mic.pin = 0x19;
14139 spec->int_mic.mux_idx = 1;
14140 spec->auto_mic = 1;
14141}
14142
Kailang Yang84898e82010-02-04 14:16:14 +010014143static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014144{
14145 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014146 spec->autocfg.hp_pins[0] = 0x15;
14147 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014148 spec->automute_mixer_nid[0] = 0x0c;
14149 spec->automute = 1;
14150 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014151 spec->ext_mic.pin = 0x18;
14152 spec->ext_mic.mux_idx = 0;
14153 spec->int_mic.pin = 0x12;
14154 spec->int_mic.mux_idx = 5;
14155 spec->auto_mic = 1;
14156}
14157
Kailang Yang226b1ec2010-04-09 11:01:20 +020014158static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014159{
14160 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014161 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014162 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014163 spec->automute_mixer_nid[0] = 0x0c;
14164 spec->automute = 1;
14165 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014166 spec->ext_mic.pin = 0x18;
14167 spec->ext_mic.mux_idx = 0;
14168 spec->int_mic.pin = 0x19;
14169 spec->int_mic.mux_idx = 1;
14170 spec->auto_mic = 1;
14171}
14172
Kailang Yang226b1ec2010-04-09 11:01:20 +020014173static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14174{
14175 struct alc_spec *spec = codec->spec;
14176 spec->autocfg.hp_pins[0] = 0x21;
14177 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014178 spec->automute_mixer_nid[0] = 0x0c;
14179 spec->automute = 1;
14180 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014181 spec->ext_mic.pin = 0x18;
14182 spec->ext_mic.mux_idx = 0;
14183 spec->int_mic.pin = 0x12;
14184 spec->int_mic.mux_idx = 6;
14185 spec->auto_mic = 1;
14186}
14187
Kailang Yangf6a92242007-12-13 16:52:54 +010014188/*
14189 * generic initialization of ADC, input mixers and output mixers
14190 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014191static const struct hda_verb alc269_init_verbs[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014192 /*
14193 * Unmute ADC0 and set the default input to mic-in
14194 */
Kailang Yang84898e82010-02-04 14:16:14 +010014195 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014196
14197 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014198 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014199 */
14200 /* set vol=0 to output mixers */
14201 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14202 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14203
14204 /* set up input amps for analog loopback */
14205 /* Amp Indices: DAC = 0, mixer = 1 */
14206 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14207 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14208 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14209 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14210 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14211 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14212
14213 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14214 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14215 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14216 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14217 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14218 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14219 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14220
14221 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14222 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014223
Kailang Yang84898e82010-02-04 14:16:14 +010014224 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014225 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14226 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014227 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014228
14229 /* set EAPD */
14230 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014231 { }
14232};
14233
Takashi Iwaia9111322011-05-02 11:30:18 +020014234static const struct hda_verb alc269vb_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014235 /*
14236 * Unmute ADC0 and set the default input to mic-in
14237 */
14238 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14239
14240 /*
14241 * Set up output mixers (0x02 - 0x03)
14242 */
14243 /* set vol=0 to output mixers */
14244 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14245 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14246
14247 /* set up input amps for analog loopback */
14248 /* Amp Indices: DAC = 0, mixer = 1 */
14249 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14250 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14251 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14252 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14253 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14254 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14255
14256 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14257 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14258 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14259 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14260 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14261 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14262 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14263
14264 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14265 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14266
14267 /* FIXME: use Mux-type input source selection */
14268 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14269 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14270 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14271
14272 /* set EAPD */
14273 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014274 { }
14275};
14276
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014277#define alc269_auto_create_multi_out_ctls \
14278 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014279#define alc269_auto_create_input_ctls \
14280 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014281
14282#ifdef CONFIG_SND_HDA_POWER_SAVE
14283#define alc269_loopbacks alc880_loopbacks
14284#endif
14285
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014286/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014287#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14288#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14289#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14290#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14291
Takashi Iwaia9111322011-05-02 11:30:18 +020014292static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014293 .substreams = 1,
14294 .channels_min = 2,
14295 .channels_max = 8,
14296 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14297 /* NID is set in alc_build_pcms */
14298 .ops = {
14299 .open = alc880_playback_pcm_open,
14300 .prepare = alc880_playback_pcm_prepare,
14301 .cleanup = alc880_playback_pcm_cleanup
14302 },
14303};
14304
Takashi Iwaia9111322011-05-02 11:30:18 +020014305static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014306 .substreams = 1,
14307 .channels_min = 2,
14308 .channels_max = 2,
14309 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14310 /* NID is set in alc_build_pcms */
14311};
14312
Takashi Iwaiad358792010-03-30 18:00:59 +020014313#ifdef CONFIG_SND_HDA_POWER_SAVE
14314static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14315{
14316 switch (codec->subsystem_id) {
14317 case 0x103c1586:
14318 return 1;
14319 }
14320 return 0;
14321}
14322
14323static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14324{
14325 /* update mute-LED according to the speaker mute state */
14326 if (nid == 0x01 || nid == 0x14) {
14327 int pinval;
14328 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14329 HDA_AMP_MUTE)
14330 pinval = 0x24;
14331 else
14332 pinval = 0x20;
14333 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a542010-03-30 18:03:44 +020014334 snd_hda_codec_update_cache(codec, 0x19, 0,
14335 AC_VERB_SET_PIN_WIDGET_CONTROL,
14336 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014337 }
14338 return alc_check_power_status(codec, nid);
14339}
14340#endif /* CONFIG_SND_HDA_POWER_SAVE */
14341
Takashi Iwai840b64c2010-07-13 22:49:01 +020014342static int alc275_setup_dual_adc(struct hda_codec *codec)
14343{
14344 struct alc_spec *spec = codec->spec;
14345
14346 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14347 return 0;
14348 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14349 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14350 if (spec->ext_mic.pin <= 0x12) {
14351 spec->private_adc_nids[0] = 0x08;
14352 spec->private_adc_nids[1] = 0x11;
14353 spec->private_capsrc_nids[0] = 0x23;
14354 spec->private_capsrc_nids[1] = 0x22;
14355 } else {
14356 spec->private_adc_nids[0] = 0x11;
14357 spec->private_adc_nids[1] = 0x08;
14358 spec->private_capsrc_nids[0] = 0x22;
14359 spec->private_capsrc_nids[1] = 0x23;
14360 }
14361 spec->adc_nids = spec->private_adc_nids;
14362 spec->capsrc_nids = spec->private_capsrc_nids;
14363 spec->num_adc_nids = 2;
14364 spec->dual_adc_switch = 1;
14365 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14366 spec->adc_nids[0], spec->adc_nids[1]);
14367 return 1;
14368 }
14369 return 0;
14370}
14371
Takashi Iwaid433a672010-09-20 15:11:54 +020014372/* different alc269-variants */
14373enum {
Kailang Yangb6878572011-07-06 09:51:29 +020014374 ALC269_TYPE_ALC269VA,
Kailang Yang48c88e82010-11-23 08:56:16 +010014375 ALC269_TYPE_ALC269VB,
Kailang Yangb6878572011-07-06 09:51:29 +020014376 ALC269_TYPE_ALC269VC,
Takashi Iwaid433a672010-09-20 15:11:54 +020014377};
14378
Kailang Yangf6a92242007-12-13 16:52:54 +010014379/*
14380 * BIOS auto configuration
14381 */
14382static int alc269_parse_auto_config(struct hda_codec *codec)
14383{
14384 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014385 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014386 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Kailang Yangf6a92242007-12-13 16:52:54 +010014387
14388 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14389 alc269_ignore);
14390 if (err < 0)
14391 return err;
14392
14393 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14394 if (err < 0)
14395 return err;
Kailang Yangb6878572011-07-06 09:51:29 +020014396 if (spec->codec_variant == ALC269_TYPE_ALC269VA)
Takashi Iwaif3550d12010-09-20 15:09:03 +020014397 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14398 else
14399 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14400 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014401 if (err < 0)
14402 return err;
14403
14404 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14405
Takashi Iwai757899a2010-07-30 10:48:14 +020014406 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014407
Takashi Iwai603c4012008-07-30 15:01:44 +020014408 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014409 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014410
Kailang Yangb6878572011-07-06 09:51:29 +020014411 if (spec->codec_variant != ALC269_TYPE_ALC269VA)
Kailang Yang6227cdc2010-02-25 08:36:52 +010014412 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020014413 else
Kailang Yang6227cdc2010-02-25 08:36:52 +010014414 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014415
Kailang Yangf6a92242007-12-13 16:52:54 +010014416 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014417 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014418
14419 if (!alc275_setup_dual_adc(codec))
14420 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14421 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014422
Kailang Yangf6a92242007-12-13 16:52:54 +010014423 err = alc_auto_add_mic_boost(codec);
14424 if (err < 0)
14425 return err;
14426
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014427 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014428 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014429
Kailang Yangf6a92242007-12-13 16:52:54 +010014430 return 1;
14431}
14432
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014433#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14434#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014435#define alc269_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010014436#define alc269_auto_init_input_src alc882_auto_init_input_src
Kailang Yangf6a92242007-12-13 16:52:54 +010014437
14438
14439/* init callback for auto-configuration model -- overriding the default init */
14440static void alc269_auto_init(struct hda_codec *codec)
14441{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014442 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014443 alc269_auto_init_multi_out(codec);
14444 alc269_auto_init_hp_out(codec);
14445 alc269_auto_init_analog_input(codec);
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010014446 if (!spec->dual_adc_switch)
14447 alc269_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014448 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014449 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014450 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014451}
14452
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014453static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14454{
14455 int val = alc_read_coef_idx(codec, 0x04);
14456 if (power_up)
14457 val |= 1 << 11;
14458 else
14459 val &= ~(1 << 11);
14460 alc_write_coef_idx(codec, 0x04, val);
14461}
14462
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014463static void alc269_shutup(struct hda_codec *codec)
Kailang Yang977ddd62010-09-15 10:02:29 +020014464{
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014465 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14466 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014467 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014468 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014469 msleep(150);
14470 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014471}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014472
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014473#ifdef SND_HDA_NEEDS_RESUME
Kailang Yang977ddd62010-09-15 10:02:29 +020014474static int alc269_resume(struct hda_codec *codec)
14475{
Kailang Yang977ddd62010-09-15 10:02:29 +020014476 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014477 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014478 msleep(150);
14479 }
14480
14481 codec->patch_ops.init(codec);
14482
14483 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014484 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014485 msleep(200);
14486 }
14487
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014488 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14489 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014490
14491 snd_hda_codec_resume_amp(codec);
14492 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014493 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014494 return 0;
14495}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014496#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014497
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014498static void alc269_fixup_hweq(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014499 const struct alc_fixup *fix, int action)
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014500{
14501 int coef;
14502
Takashi Iwai58701122011-01-13 15:41:45 +010014503 if (action != ALC_FIXUP_ACT_INIT)
Takashi Iwai9fb1ef22011-01-13 14:40:43 +010014504 return;
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014505 coef = alc_read_coef_idx(codec, 0x1e);
14506 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
14507}
14508
Takashi Iwai6981d182011-04-15 10:11:12 +020014509static void alc271_fixup_dmic(struct hda_codec *codec,
14510 const struct alc_fixup *fix, int action)
14511{
Takashi Iwaia9111322011-05-02 11:30:18 +020014512 static const struct hda_verb verbs[] = {
Takashi Iwai6981d182011-04-15 10:11:12 +020014513 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14514 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14515 {}
14516 };
14517 unsigned int cfg;
14518
14519 if (strcmp(codec->chip_name, "ALC271X"))
14520 return;
14521 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
14522 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
14523 snd_hda_sequence_write(codec, verbs);
14524}
14525
Takashi Iwaiff818c22010-04-12 08:59:25 +020014526enum {
14527 ALC269_FIXUP_SONY_VAIO,
Takashi Iwai74dc8902011-01-13 14:14:41 +010014528 ALC275_FIXUP_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014529 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014530 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014531 ALC269_FIXUP_ASUS_G73JW,
Kailang Yang357f9152011-01-12 08:12:52 +010014532 ALC269_FIXUP_LENOVO_EAPD,
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014533 ALC275_FIXUP_SONY_HWEQ,
Takashi Iwai6981d182011-04-15 10:11:12 +020014534 ALC271_FIXUP_DMIC,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014535};
14536
Takashi Iwaiff818c22010-04-12 08:59:25 +020014537static const struct alc_fixup alc269_fixups[] = {
14538 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014539 .type = ALC_FIXUP_VERBS,
14540 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020014541 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14542 {}
14543 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014544 },
Takashi Iwai74dc8902011-01-13 14:14:41 +010014545 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014546 .type = ALC_FIXUP_VERBS,
14547 .v.verbs = (const struct hda_verb[]) {
Kailang Yang27855912010-12-21 09:09:53 +010014548 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14549 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14550 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14551 { }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014552 },
14553 .chained = true,
14554 .chain_id = ALC269_FIXUP_SONY_VAIO
Kailang Yang27855912010-12-21 09:09:53 +010014555 },
David Henningsson145a9022010-09-16 10:07:53 +020014556 [ALC269_FIXUP_DELL_M101Z] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014557 .type = ALC_FIXUP_VERBS,
14558 .v.verbs = (const struct hda_verb[]) {
David Henningsson145a9022010-09-16 10:07:53 +020014559 /* Enables internal speaker */
14560 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14561 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14562 {}
14563 }
14564 },
David Henningsson022c92b2010-12-17 20:43:04 +010014565 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014566 .type = ALC_FIXUP_SKU,
14567 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonfe67b242010-12-15 08:01:46 +010014568 },
David Henningssonac612402010-12-15 09:18:18 +010014569 [ALC269_FIXUP_ASUS_G73JW] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014570 .type = ALC_FIXUP_PINS,
14571 .v.pins = (const struct alc_pincfg[]) {
David Henningssonac612402010-12-15 09:18:18 +010014572 { 0x17, 0x99130111 }, /* subwoofer */
14573 { }
14574 }
14575 },
Kailang Yang357f9152011-01-12 08:12:52 +010014576 [ALC269_FIXUP_LENOVO_EAPD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014577 .type = ALC_FIXUP_VERBS,
14578 .v.verbs = (const struct hda_verb[]) {
Kailang Yang357f9152011-01-12 08:12:52 +010014579 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
14580 {}
14581 }
14582 },
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014583 [ALC275_FIXUP_SONY_HWEQ] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014584 .type = ALC_FIXUP_FUNC,
14585 .v.func = alc269_fixup_hweq,
14586 .chained = true,
14587 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
Takashi Iwai6981d182011-04-15 10:11:12 +020014588 },
14589 [ALC271_FIXUP_DMIC] = {
14590 .type = ALC_FIXUP_FUNC,
14591 .v.func = alc271_fixup_dmic,
14592 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014593};
14594
Takashi Iwaia9111322011-05-02 11:30:18 +020014595static const struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai74dc8902011-01-13 14:14:41 +010014596 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014597 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
14598 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
Takashi Iwai7039c742010-12-23 16:35:34 +010014599 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014600 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Takashi Iwai6981d182011-04-15 10:11:12 +020014601 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
David Henningsson022c92b2010-12-17 20:43:04 +010014602 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonded9f522011-01-26 11:46:12 +010014603 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
14604 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
14605 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
14606 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014607 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Kailang Yang357f9152011-01-12 08:12:52 +010014608 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014609 {}
14610};
14611
14612
Kailang Yangf6a92242007-12-13 16:52:54 +010014613/*
14614 * configuration and preset
14615 */
Takashi Iwaiea734962011-01-17 11:29:34 +010014616static const char * const alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014617 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014618 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014619 [ALC269_AMIC] = "laptop-amic",
14620 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014621 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014622 [ALC269_LIFEBOOK] = "lifebook",
14623 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014624};
14625
Takashi Iwaia9111322011-05-02 11:30:18 +020014626static const struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014627 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014628 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020014629 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014630 ALC269_AMIC),
14631 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14632 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14633 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14634 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14635 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14636 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14637 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14638 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14639 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
Chih-Wei Huangc790ad32011-02-25 11:14:31 +080014640 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
Kailang Yang84898e82010-02-04 14:16:14 +010014641 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14642 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14643 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14644 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14645 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14646 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14647 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14648 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14649 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14650 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14651 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14652 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14653 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14654 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14655 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14656 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14657 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14658 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14659 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14660 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14661 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14662 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14663 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14664 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14665 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14666 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014667 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014668 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014669 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014670 ALC269_DMIC),
14671 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14672 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014673 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014674 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014675 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14676 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14677 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14678 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14679 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14680 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014681 {}
14682};
14683
Takashi Iwaia9111322011-05-02 11:30:18 +020014684static const struct alc_config_preset alc269_presets[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014685 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014686 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014687 .init_verbs = { alc269_init_verbs },
14688 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14689 .dac_nids = alc269_dac_nids,
14690 .hp_nid = 0x03,
14691 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14692 .channel_mode = alc269_modes,
14693 .input_mux = &alc269_capture_source,
14694 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014695 [ALC269_QUANTA_FL1] = {
14696 .mixers = { alc269_quanta_fl1_mixer },
14697 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14698 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14699 .dac_nids = alc269_dac_nids,
14700 .hp_nid = 0x03,
14701 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14702 .channel_mode = alc269_modes,
14703 .input_mux = &alc269_capture_source,
14704 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014705 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014706 .init_hook = alc269_quanta_fl1_init_hook,
14707 },
Kailang Yang84898e82010-02-04 14:16:14 +010014708 [ALC269_AMIC] = {
14709 .mixers = { alc269_laptop_mixer },
14710 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014711 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014712 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014713 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14714 .dac_nids = alc269_dac_nids,
14715 .hp_nid = 0x03,
14716 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14717 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014718 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014719 .setup = alc269_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014720 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014721 },
Kailang Yang84898e82010-02-04 14:16:14 +010014722 [ALC269_DMIC] = {
14723 .mixers = { alc269_laptop_mixer },
14724 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014725 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014726 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014727 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14728 .dac_nids = alc269_dac_nids,
14729 .hp_nid = 0x03,
14730 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14731 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014732 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014733 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014734 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010014735 },
14736 [ALC269VB_AMIC] = {
14737 .mixers = { alc269vb_laptop_mixer },
14738 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14739 .init_verbs = { alc269vb_init_verbs,
14740 alc269vb_laptop_amic_init_verbs },
14741 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14742 .dac_nids = alc269_dac_nids,
14743 .hp_nid = 0x03,
14744 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14745 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014746 .unsol_event = alc_sku_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014747 .setup = alc269vb_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014748 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010014749 },
14750 [ALC269VB_DMIC] = {
14751 .mixers = { alc269vb_laptop_mixer },
14752 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14753 .init_verbs = { alc269vb_init_verbs,
14754 alc269vb_laptop_dmic_init_verbs },
14755 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14756 .dac_nids = alc269_dac_nids,
14757 .hp_nid = 0x03,
14758 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14759 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014760 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014761 .setup = alc269vb_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014762 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014763 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014764 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014765 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014766 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014767 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014768 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014769 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14770 .dac_nids = alc269_dac_nids,
14771 .hp_nid = 0x03,
14772 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14773 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014774 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014775 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014776 .init_hook = alc_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014777 },
Tony Vroon64154832008-11-06 15:08:49 +000014778 [ALC269_LIFEBOOK] = {
14779 .mixers = { alc269_lifebook_mixer },
14780 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14781 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14782 .dac_nids = alc269_dac_nids,
14783 .hp_nid = 0x03,
14784 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14785 .channel_mode = alc269_modes,
14786 .input_mux = &alc269_capture_source,
14787 .unsol_event = alc269_lifebook_unsol_event,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014788 .setup = alc269_lifebook_setup,
Tony Vroon64154832008-11-06 15:08:49 +000014789 .init_hook = alc269_lifebook_init_hook,
14790 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014791 [ALC271_ACER] = {
14792 .mixers = { alc269_asus_mixer },
14793 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14794 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
14795 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14796 .dac_nids = alc269_dac_nids,
14797 .adc_nids = alc262_dmic_adc_nids,
14798 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
14799 .capsrc_nids = alc262_dmic_capsrc_nids,
14800 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14801 .channel_mode = alc269_modes,
14802 .input_mux = &alc269_capture_source,
14803 .dig_out_nid = ALC880_DIGOUT_NID,
14804 .unsol_event = alc_sku_unsol_event,
14805 .setup = alc269vb_laptop_dmic_setup,
14806 .init_hook = alc_inithook,
14807 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014808};
14809
Kailang Yang977ddd62010-09-15 10:02:29 +020014810static int alc269_fill_coef(struct hda_codec *codec)
14811{
14812 int val;
14813
14814 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
14815 alc_write_coef_idx(codec, 0xf, 0x960b);
14816 alc_write_coef_idx(codec, 0xe, 0x8817);
14817 }
14818
14819 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
14820 alc_write_coef_idx(codec, 0xf, 0x960b);
14821 alc_write_coef_idx(codec, 0xe, 0x8814);
14822 }
14823
14824 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
14825 val = alc_read_coef_idx(codec, 0x04);
14826 /* Power up output pin */
14827 alc_write_coef_idx(codec, 0x04, val | (1<<11));
14828 }
14829
14830 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
14831 val = alc_read_coef_idx(codec, 0xd);
14832 if ((val & 0x0c00) >> 10 != 0x1) {
14833 /* Capless ramp up clock control */
Kailang Yangb896b4e2011-05-18 11:53:16 +020014834 alc_write_coef_idx(codec, 0xd, val | (1<<10));
Kailang Yang977ddd62010-09-15 10:02:29 +020014835 }
14836 val = alc_read_coef_idx(codec, 0x17);
14837 if ((val & 0x01c0) >> 6 != 0x4) {
14838 /* Class D power on reset */
Kailang Yangb896b4e2011-05-18 11:53:16 +020014839 alc_write_coef_idx(codec, 0x17, val | (1<<7));
Kailang Yang977ddd62010-09-15 10:02:29 +020014840 }
14841 }
Kailang Yangb896b4e2011-05-18 11:53:16 +020014842
14843 val = alc_read_coef_idx(codec, 0xd); /* Class D */
14844 alc_write_coef_idx(codec, 0xd, val | (1<<14));
14845
14846 val = alc_read_coef_idx(codec, 0x4); /* HP */
14847 alc_write_coef_idx(codec, 0x4, val | (1<<11));
14848
Kailang Yang977ddd62010-09-15 10:02:29 +020014849 return 0;
14850}
14851
Kailang Yangf6a92242007-12-13 16:52:54 +010014852static int patch_alc269(struct hda_codec *codec)
14853{
14854 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010014855 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010014856 int err;
14857
14858 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14859 if (spec == NULL)
14860 return -ENOMEM;
14861
14862 codec->spec = spec;
14863
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020014864 spec->mixer_nid = 0x0b;
14865
Kailang Yangda00c242010-03-19 11:23:45 +010014866 alc_auto_parse_customize_define(codec);
14867
Kailang Yangc793bec2010-12-21 09:14:13 +010014868 if (codec->vendor_id == 0x10ec0269) {
Kailang Yangb6878572011-07-06 09:51:29 +020014869 spec->codec_variant = ALC269_TYPE_ALC269VA;
Kailang Yangc793bec2010-12-21 09:14:13 +010014870 coef = alc_read_coef_idx(codec, 0);
14871 if ((coef & 0x00f0) == 0x0010) {
14872 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14873 spec->cdefine.platform_type == 1) {
14874 alc_codec_rename(codec, "ALC271X");
Kailang Yangc793bec2010-12-21 09:14:13 +010014875 } else if ((coef & 0xf000) == 0x2000) {
14876 alc_codec_rename(codec, "ALC259");
Kailang Yangc793bec2010-12-21 09:14:13 +010014877 } else if ((coef & 0xf000) == 0x3000) {
14878 alc_codec_rename(codec, "ALC258");
Kailang Yangb6878572011-07-06 09:51:29 +020014879 } else if ((coef & 0xfff0) == 0x3010) {
14880 alc_codec_rename(codec, "ALC277");
Kailang Yangc793bec2010-12-21 09:14:13 +010014881 } else {
14882 alc_codec_rename(codec, "ALC269VB");
Kailang Yangc793bec2010-12-21 09:14:13 +010014883 }
Kailang Yangb6878572011-07-06 09:51:29 +020014884 spec->codec_variant = ALC269_TYPE_ALC269VB;
14885 } else if ((coef & 0x00f0) == 0x0020) {
14886 if (coef == 0xa023)
14887 alc_codec_rename(codec, "ALC259");
14888 else if (coef == 0x6023)
14889 alc_codec_rename(codec, "ALC281X");
14890 else if (codec->bus->pci->subsystem_vendor == 0x17aa &&
14891 codec->bus->pci->subsystem_device == 0x21f3)
14892 alc_codec_rename(codec, "ALC3202");
14893 else
14894 alc_codec_rename(codec, "ALC269VC");
14895 spec->codec_variant = ALC269_TYPE_ALC269VC;
Kailang Yangc793bec2010-12-21 09:14:13 +010014896 } else
14897 alc_fix_pll_init(codec, 0x20, 0x04, 15);
14898 alc269_fill_coef(codec);
14899 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014900
Kailang Yangf6a92242007-12-13 16:52:54 +010014901 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14902 alc269_models,
14903 alc269_cfg_tbl);
14904
14905 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014906 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14907 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014908 board_config = ALC269_AUTO;
14909 }
14910
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014911 if (board_config == ALC269_AUTO) {
14912 alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
14913 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
14914 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014915
Kailang Yangf6a92242007-12-13 16:52:54 +010014916 if (board_config == ALC269_AUTO) {
14917 /* automatic parse from the BIOS config */
14918 err = alc269_parse_auto_config(codec);
14919 if (err < 0) {
14920 alc_free(codec);
14921 return err;
14922 } else if (!err) {
14923 printk(KERN_INFO
14924 "hda_codec: Cannot set up configuration "
14925 "from BIOS. Using base mode...\n");
14926 board_config = ALC269_BASIC;
14927 }
14928 }
14929
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014930 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020014931 err = snd_hda_attach_beep_device(codec, 0x1);
14932 if (err < 0) {
14933 alc_free(codec);
14934 return err;
14935 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014936 }
14937
Kailang Yangf6a92242007-12-13 16:52:54 +010014938 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014939 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014940
Kailang Yang84898e82010-02-04 14:16:14 +010014941 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014942 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14943 * fix the sample rate of analog I/O to 44.1kHz
14944 */
14945 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14946 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020014947 } else if (spec->dual_adc_switch) {
14948 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14949 /* switch ADC dynamically */
14950 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014951 } else {
14952 spec->stream_analog_playback = &alc269_pcm_analog_playback;
14953 spec->stream_analog_capture = &alc269_pcm_analog_capture;
14954 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014955 spec->stream_digital_playback = &alc269_pcm_digital_playback;
14956 spec->stream_digital_capture = &alc269_pcm_digital_capture;
14957
Takashi Iwai66946352010-03-29 17:21:45 +020014958 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Kailang Yangb6878572011-07-06 09:51:29 +020014959 if (spec->codec_variant == ALC269_TYPE_ALC269VA) {
Takashi Iwai66946352010-03-29 17:21:45 +020014960 spec->adc_nids = alc269_adc_nids;
14961 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
14962 spec->capsrc_nids = alc269_capsrc_nids;
14963 } else {
14964 spec->adc_nids = alc269vb_adc_nids;
14965 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
14966 spec->capsrc_nids = alc269vb_capsrc_nids;
14967 }
Kailang Yang84898e82010-02-04 14:16:14 +010014968 }
14969
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014970 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014971 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014972 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010014973 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014974
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014975 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaiff818c22010-04-12 08:59:25 +020014976
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014977 spec->vmaster_nid = 0x02;
14978
Kailang Yangf6a92242007-12-13 16:52:54 +010014979 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020014980#ifdef SND_HDA_NEEDS_RESUME
14981 codec->patch_ops.resume = alc269_resume;
14982#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010014983 if (board_config == ALC269_AUTO)
14984 spec->init_hook = alc269_auto_init;
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014985 spec->shutup = alc269_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020014986
14987 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014988#ifdef CONFIG_SND_HDA_POWER_SAVE
14989 if (!spec->loopback.amplist)
14990 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014991 if (alc269_mic2_for_mute_led(codec))
14992 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014993#endif
14994
14995 return 0;
14996}
14997
14998/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014999 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15000 */
15001
15002/*
15003 * set the path ways for 2 channel output
15004 * need to set the codec line out and mic 1 pin widgets to inputs
15005 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015006static const struct hda_verb alc861_threestack_ch2_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015007 /* set pin widget 1Ah (line in) for input */
15008 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015009 /* set pin widget 18h (mic1/2) for input, for mic also enable
15010 * the vref
15011 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015012 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15013
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015014 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15015#if 0
15016 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15017 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15018#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015019 { } /* end */
15020};
15021/*
15022 * 6ch mode
15023 * need to set the codec line out and mic 1 pin widgets to outputs
15024 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015025static const struct hda_verb alc861_threestack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015026 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15027 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15028 /* set pin widget 18h (mic1) for output (CLFE)*/
15029 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15030
15031 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015032 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015033
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015034 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15035#if 0
15036 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15037 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15038#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015039 { } /* end */
15040};
15041
Takashi Iwaia9111322011-05-02 11:30:18 +020015042static const struct hda_channel_mode alc861_threestack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015043 { 2, alc861_threestack_ch2_init },
15044 { 6, alc861_threestack_ch6_init },
15045};
Takashi Iwai22309c32006-08-09 16:57:28 +020015046/* Set mic1 as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015047static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015048 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15049 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15050 { } /* end */
15051};
15052/* Set mic1 as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015053static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015054 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15055 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15056 { } /* end */
15057};
15058
Takashi Iwaia9111322011-05-02 11:30:18 +020015059static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015060 { 2, alc861_uniwill_m31_ch2_init },
15061 { 4, alc861_uniwill_m31_ch4_init },
15062};
Kailang Yangdf694da2005-12-05 19:42:22 +010015063
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015064/* Set mic1 and line-in as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015065static const struct hda_verb alc861_asus_ch2_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015066 /* set pin widget 1Ah (line in) for input */
15067 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015068 /* set pin widget 18h (mic1/2) for input, for mic also enable
15069 * the vref
15070 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015071 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15072
15073 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15074#if 0
15075 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15076 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15077#endif
15078 { } /* end */
15079};
15080/* Set mic1 nad line-in as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015081static const struct hda_verb alc861_asus_ch6_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015082 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15083 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15084 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15085 /* set pin widget 18h (mic1) for output (CLFE)*/
15086 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15087 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15088 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15089 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15090
15091 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15092#if 0
15093 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15094 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15095#endif
15096 { } /* end */
15097};
15098
Takashi Iwaia9111322011-05-02 11:30:18 +020015099static const struct hda_channel_mode alc861_asus_modes[2] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015100 { 2, alc861_asus_ch2_init },
15101 { 6, alc861_asus_ch6_init },
15102};
15103
Kailang Yangdf694da2005-12-05 19:42:22 +010015104/* patch-ALC861 */
15105
Takashi Iwaia9111322011-05-02 11:30:18 +020015106static const struct snd_kcontrol_new alc861_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015107 /* output mixer control */
15108 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15109 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15110 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15111 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15112 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15113
15114 /*Input mixer control */
15115 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15116 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15117 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15118 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15119 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15120 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15121 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15122 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15123 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15124 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015125
Kailang Yangdf694da2005-12-05 19:42:22 +010015126 { } /* end */
15127};
15128
Takashi Iwaia9111322011-05-02 11:30:18 +020015129static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015130 /* output mixer control */
15131 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15132 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15133 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15134 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15135 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15136
15137 /* Input mixer control */
15138 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15139 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15140 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15141 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15142 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15143 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15144 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15145 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15146 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15147 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015148
Kailang Yangdf694da2005-12-05 19:42:22 +010015149 {
15150 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15151 .name = "Channel Mode",
15152 .info = alc_ch_mode_info,
15153 .get = alc_ch_mode_get,
15154 .put = alc_ch_mode_put,
15155 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15156 },
15157 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015158};
15159
Takashi Iwaia9111322011-05-02 11:30:18 +020015160static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015161 /* output mixer control */
15162 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15163 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15164 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015165
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015166 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015167};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015168
Takashi Iwaia9111322011-05-02 11:30:18 +020015169static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015170 /* output mixer control */
15171 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15172 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15173 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15174 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15175 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15176
15177 /* Input mixer control */
15178 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15179 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15180 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15181 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15182 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15183 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15184 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15185 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15186 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15187 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015188
Takashi Iwai22309c32006-08-09 16:57:28 +020015189 {
15190 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15191 .name = "Channel Mode",
15192 .info = alc_ch_mode_info,
15193 .get = alc_ch_mode_get,
15194 .put = alc_ch_mode_put,
15195 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15196 },
15197 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015198};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015199
Takashi Iwaia9111322011-05-02 11:30:18 +020015200static const struct snd_kcontrol_new alc861_asus_mixer[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015201 /* output mixer control */
15202 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15203 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15204 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15205 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15206 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15207
15208 /* Input mixer control */
15209 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15210 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15211 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15212 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15213 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15214 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15215 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15216 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15217 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015218 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15219
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015220 {
15221 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15222 .name = "Channel Mode",
15223 .info = alc_ch_mode_info,
15224 .get = alc_ch_mode_get,
15225 .put = alc_ch_mode_put,
15226 .private_value = ARRAY_SIZE(alc861_asus_modes),
15227 },
15228 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015229};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015230
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015231/* additional mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015232static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015233 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15234 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015235 { }
15236};
15237
Kailang Yangdf694da2005-12-05 19:42:22 +010015238/*
15239 * generic initialization of ADC, input mixers and output mixers
15240 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015241static const struct hda_verb alc861_base_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015242 /*
15243 * Unmute ADC0 and set the default input to mic-in
15244 */
15245 /* port-A for surround (rear panel) */
15246 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15247 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15248 /* port-B for mic-in (rear panel) with vref */
15249 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15250 /* port-C for line-in (rear panel) */
15251 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15252 /* port-D for Front */
15253 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15254 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15255 /* port-E for HP out (front panel) */
15256 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15257 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015258 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015259 /* port-F for mic-in (front panel) with vref */
15260 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15261 /* port-G for CLFE (rear panel) */
15262 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15263 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15264 /* port-H for side (rear panel) */
15265 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15266 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15267 /* CD-in */
15268 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15269 /* route front mic to ADC1*/
15270 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15271 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015272
Kailang Yangdf694da2005-12-05 19:42:22 +010015273 /* Unmute DAC0~3 & spdif out*/
15274 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15275 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15276 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15277 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15278 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015279
Kailang Yangdf694da2005-12-05 19:42:22 +010015280 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15281 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15282 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15283 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15284 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015285
Kailang Yangdf694da2005-12-05 19:42:22 +010015286 /* Unmute Stereo Mixer 15 */
15287 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15288 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15289 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015290 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015291
15292 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15293 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15294 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15295 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15296 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15297 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15298 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15299 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015300 /* hp used DAC 3 (Front) */
15301 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015302 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15303
15304 { }
15305};
15306
Takashi Iwaia9111322011-05-02 11:30:18 +020015307static const struct hda_verb alc861_threestack_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015308 /*
15309 * Unmute ADC0 and set the default input to mic-in
15310 */
15311 /* port-A for surround (rear panel) */
15312 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15313 /* port-B for mic-in (rear panel) with vref */
15314 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15315 /* port-C for line-in (rear panel) */
15316 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15317 /* port-D for Front */
15318 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15319 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15320 /* port-E for HP out (front panel) */
15321 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15322 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015323 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015324 /* port-F for mic-in (front panel) with vref */
15325 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15326 /* port-G for CLFE (rear panel) */
15327 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15328 /* port-H for side (rear panel) */
15329 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15330 /* CD-in */
15331 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15332 /* route front mic to ADC1*/
15333 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15334 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15335 /* Unmute DAC0~3 & spdif out*/
15336 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15337 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15338 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15339 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15340 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015341
Kailang Yangdf694da2005-12-05 19:42:22 +010015342 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15343 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15344 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15345 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15346 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015347
Kailang Yangdf694da2005-12-05 19:42:22 +010015348 /* Unmute Stereo Mixer 15 */
15349 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15350 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15351 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015352 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015353
15354 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15355 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15356 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15357 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15358 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15359 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15360 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15361 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015362 /* hp used DAC 3 (Front) */
15363 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015364 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15365 { }
15366};
Takashi Iwai22309c32006-08-09 16:57:28 +020015367
Takashi Iwaia9111322011-05-02 11:30:18 +020015368static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015369 /*
15370 * Unmute ADC0 and set the default input to mic-in
15371 */
15372 /* port-A for surround (rear panel) */
15373 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15374 /* port-B for mic-in (rear panel) with vref */
15375 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15376 /* port-C for line-in (rear panel) */
15377 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15378 /* port-D for Front */
15379 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15380 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15381 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015382 /* this has to be set to VREF80 */
15383 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015384 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015385 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015386 /* port-F for mic-in (front panel) with vref */
15387 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15388 /* port-G for CLFE (rear panel) */
15389 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15390 /* port-H for side (rear panel) */
15391 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15392 /* CD-in */
15393 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15394 /* route front mic to ADC1*/
15395 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15396 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15397 /* Unmute DAC0~3 & spdif out*/
15398 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15399 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15400 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15401 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15402 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015403
Takashi Iwai22309c32006-08-09 16:57:28 +020015404 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15405 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15406 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15407 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15408 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015409
Takashi Iwai22309c32006-08-09 16:57:28 +020015410 /* Unmute Stereo Mixer 15 */
15411 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15412 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15413 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015414 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015415
15416 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15417 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15418 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15419 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15420 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15421 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15422 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15423 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015424 /* hp used DAC 3 (Front) */
15425 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015426 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15427 { }
15428};
15429
Takashi Iwaia9111322011-05-02 11:30:18 +020015430static const struct hda_verb alc861_asus_init_verbs[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015431 /*
15432 * Unmute ADC0 and set the default input to mic-in
15433 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015434 /* port-A for surround (rear panel)
15435 * according to codec#0 this is the HP jack
15436 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015437 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15438 /* route front PCM to HP */
15439 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15440 /* port-B for mic-in (rear panel) with vref */
15441 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15442 /* port-C for line-in (rear panel) */
15443 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15444 /* port-D for Front */
15445 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15446 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15447 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015448 /* this has to be set to VREF80 */
15449 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015450 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015451 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015452 /* port-F for mic-in (front panel) with vref */
15453 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15454 /* port-G for CLFE (rear panel) */
15455 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15456 /* port-H for side (rear panel) */
15457 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15458 /* CD-in */
15459 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15460 /* route front mic to ADC1*/
15461 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15462 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15463 /* Unmute DAC0~3 & spdif out*/
15464 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15465 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15466 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15467 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15468 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15469 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15470 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15471 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15472 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15473 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015474
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015475 /* Unmute Stereo Mixer 15 */
15476 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15477 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15478 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015479 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015480
15481 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15482 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15483 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15484 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15485 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15486 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15487 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15488 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015489 /* hp used DAC 3 (Front) */
15490 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015491 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15492 { }
15493};
15494
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015495/* additional init verbs for ASUS laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020015496static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015497 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15498 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15499 { }
15500};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015501
Takashi Iwaia9111322011-05-02 11:30:18 +020015502static const struct hda_verb alc861_toshiba_init_verbs[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015503 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015504
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015505 { }
15506};
15507
15508/* toggle speaker-output according to the hp-jack state */
15509static void alc861_toshiba_automute(struct hda_codec *codec)
15510{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015511 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015512
Takashi Iwai47fd8302007-08-10 17:11:07 +020015513 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15514 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15515 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15516 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015517}
15518
15519static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15520 unsigned int res)
15521{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015522 if ((res >> 26) == ALC880_HP_EVENT)
15523 alc861_toshiba_automute(codec);
15524}
15525
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015526/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015527#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15528#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15529#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15530#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15531
15532
15533#define ALC861_DIGOUT_NID 0x07
15534
Takashi Iwaia9111322011-05-02 11:30:18 +020015535static const struct hda_channel_mode alc861_8ch_modes[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015536 { 8, NULL }
15537};
15538
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015539static const hda_nid_t alc861_dac_nids[4] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015540 /* front, surround, clfe, side */
15541 0x03, 0x06, 0x05, 0x04
15542};
15543
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015544static const hda_nid_t alc660_dac_nids[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015545 /* front, clfe, surround */
15546 0x03, 0x05, 0x06
15547};
15548
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015549static const hda_nid_t alc861_adc_nids[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015550 /* ADC0-2 */
15551 0x08,
15552};
15553
Takashi Iwaia9111322011-05-02 11:30:18 +020015554static const struct hda_input_mux alc861_capture_source = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015555 .num_items = 5,
15556 .items = {
15557 { "Mic", 0x0 },
15558 { "Front Mic", 0x3 },
15559 { "Line", 0x1 },
15560 { "CD", 0x4 },
15561 { "Mixer", 0x5 },
15562 },
15563};
15564
Takashi Iwai1c209302009-07-22 15:17:45 +020015565static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15566{
15567 struct alc_spec *spec = codec->spec;
15568 hda_nid_t mix, srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +020015569 int i, num;
Takashi Iwai1c209302009-07-22 15:17:45 +020015570
15571 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15572 return 0;
15573 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15574 if (num < 0)
15575 return 0;
15576 for (i = 0; i < num; i++) {
15577 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015578 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015579 if (type != AC_WID_AUD_OUT)
15580 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020015581 if (!found_in_nid_list(srcs[i], spec->multiout.dac_nids,
15582 spec->multiout.num_dacs))
Takashi Iwai1c209302009-07-22 15:17:45 +020015583 return srcs[i];
15584 }
15585 return 0;
15586}
15587
Kailang Yangdf694da2005-12-05 19:42:22 +010015588/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaicb053a82011-06-27 11:32:07 +020015589static int alc861_auto_fill_dac_nids(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015590{
Takashi Iwai1c209302009-07-22 15:17:45 +020015591 struct alc_spec *spec = codec->spec;
Takashi Iwaicb053a82011-06-27 11:32:07 +020015592 const struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010015593 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015594 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015595
15596 spec->multiout.dac_nids = spec->private_dac_nids;
15597 for (i = 0; i < cfg->line_outs; i++) {
15598 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015599 dac = alc861_look_for_dac(codec, nid);
15600 if (!dac)
15601 continue;
Takashi Iwaidda14412011-05-02 11:29:30 +020015602 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015603 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015604 return 0;
15605}
15606
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015607static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15608 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015609{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015610 return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015611 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15612}
15613
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015614#define alc861_create_out_sw(codec, pfx, nid, chs) \
15615 __alc861_create_out_sw(codec, pfx, nid, 0, chs)
15616
Takashi Iwai1c209302009-07-22 15:17:45 +020015617/* add playback controls from the parsed DAC table */
15618static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15619 const struct auto_pin_cfg *cfg)
15620{
15621 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015622 hda_nid_t nid;
Takashi Iwaice764ab2011-04-27 16:35:23 +020015623 int i, err, noutputs;
Takashi Iwai1c209302009-07-22 15:17:45 +020015624
Takashi Iwaice764ab2011-04-27 16:35:23 +020015625 noutputs = cfg->line_outs;
15626 if (spec->multi_ios > 0)
15627 noutputs += spec->multi_ios;
15628
15629 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020015630 const char *name;
15631 int index;
Kailang Yangdf694da2005-12-05 19:42:22 +010015632 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015633 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015634 continue;
Takashi Iwai6843ca12011-06-24 11:03:58 +020015635 name = alc_get_line_out_pfx(spec, i, true, &index);
15636 if (!name) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015637 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015638 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015639 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015640 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015641 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015642 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015643 return err;
15644 } else {
David Henningsson5a882642011-03-23 08:35:07 +010015645 err = __alc861_create_out_sw(codec, name, nid, index, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015646 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015647 return err;
15648 }
15649 }
15650 return 0;
15651}
15652
Takashi Iwai1c209302009-07-22 15:17:45 +020015653static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015654{
Takashi Iwai1c209302009-07-22 15:17:45 +020015655 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015656 int err;
15657 hda_nid_t nid;
15658
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015659 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015660 return 0;
15661
15662 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015663 nid = alc861_look_for_dac(codec, pin);
15664 if (nid) {
15665 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15666 if (err < 0)
15667 return err;
15668 spec->multiout.hp_nid = nid;
15669 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015670 }
15671 return 0;
15672}
15673
15674/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015675static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015676 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015677{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015678 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015679}
15680
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015681static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15682 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015683 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015684{
Takashi Iwai1c209302009-07-22 15:17:45 +020015685 hda_nid_t mix, srcs[5];
15686 int i, num;
15687
Jacek Luczak564c5be2008-05-03 18:41:23 +020015688 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15689 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015690 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015691 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015692 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15693 return;
15694 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15695 if (num < 0)
15696 return;
15697 for (i = 0; i < num; i++) {
15698 unsigned int mute;
15699 if (srcs[i] == dac || srcs[i] == 0x15)
15700 mute = AMP_IN_UNMUTE(i);
15701 else
15702 mute = AMP_IN_MUTE(i);
15703 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15704 mute);
15705 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015706}
15707
15708static void alc861_auto_init_multi_out(struct hda_codec *codec)
15709{
15710 struct alc_spec *spec = codec->spec;
15711 int i;
15712
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020015713 for (i = 0; i < spec->autocfg.line_outs + spec->multi_ios; i++) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015714 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015715 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015716 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015717 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015718 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015719 }
15720}
15721
15722static void alc861_auto_init_hp_out(struct hda_codec *codec)
15723{
15724 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015725
Takashi Iwai15870f02009-10-05 08:25:13 +020015726 if (spec->autocfg.hp_outs)
15727 alc861_auto_set_output_and_unmute(codec,
15728 spec->autocfg.hp_pins[0],
15729 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015730 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015731 if (spec->autocfg.speaker_outs)
15732 alc861_auto_set_output_and_unmute(codec,
15733 spec->autocfg.speaker_pins[0],
15734 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015735 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015736}
15737
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020015738#define alc861_auto_init_analog_input alc880_auto_init_analog_input
Kailang Yangdf694da2005-12-05 19:42:22 +010015739
15740/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015741/* return 1 if successful, 0 if the proper config is not found,
15742 * or a negative error code
15743 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015744static int alc861_parse_auto_config(struct hda_codec *codec)
15745{
15746 struct alc_spec *spec = codec->spec;
15747 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015748 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015749
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015750 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15751 alc861_ignore);
15752 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015753 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015754 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015755 return 0; /* can't find valid BIOS pin config */
15756
Takashi Iwaicb053a82011-06-27 11:32:07 +020015757 err = alc861_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015758 if (err < 0)
15759 return err;
Takashi Iwaicb053a82011-06-27 11:32:07 +020015760 err = alc_auto_add_multi_channel_mode(codec, alc861_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020015761 if (err < 0)
15762 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015763 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015764 if (err < 0)
15765 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015766 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015767 if (err < 0)
15768 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020015769 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015770 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015771 return err;
15772
15773 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15774
Takashi Iwai757899a2010-07-30 10:48:14 +020015775 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015776
Takashi Iwai603c4012008-07-30 15:01:44 +020015777 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015778 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015779
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020015780 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020015781 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010015782
15783 spec->adc_nids = alc861_adc_nids;
15784 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015785 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015786
Kailang Yang6227cdc2010-02-25 08:36:52 +010015787 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015788
Kailang Yangdf694da2005-12-05 19:42:22 +010015789 return 1;
15790}
15791
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015792/* additional initialization for auto-configuration model */
15793static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015794{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015795 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015796 alc861_auto_init_multi_out(codec);
15797 alc861_auto_init_hp_out(codec);
15798 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015799 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015800 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015801 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015802}
15803
Takashi Iwaicb53c622007-08-10 17:21:45 +020015804#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +020015805static const struct hda_amp_list alc861_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +020015806 { 0x15, HDA_INPUT, 0 },
15807 { 0x15, HDA_INPUT, 1 },
15808 { 0x15, HDA_INPUT, 2 },
15809 { 0x15, HDA_INPUT, 3 },
15810 { } /* end */
15811};
15812#endif
15813
Kailang Yangdf694da2005-12-05 19:42:22 +010015814
15815/*
15816 * configuration and preset
15817 */
Takashi Iwaiea734962011-01-17 11:29:34 +010015818static const char * const alc861_models[ALC861_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015819 [ALC861_3ST] = "3stack",
15820 [ALC660_3ST] = "3stack-660",
15821 [ALC861_3ST_DIG] = "3stack-dig",
15822 [ALC861_6ST_DIG] = "6stack-dig",
15823 [ALC861_UNIWILL_M31] = "uniwill-m31",
15824 [ALC861_TOSHIBA] = "toshiba",
15825 [ALC861_ASUS] = "asus",
15826 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15827 [ALC861_AUTO] = "auto",
15828};
15829
Takashi Iwaia9111322011-05-02 11:30:18 +020015830static const struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015831 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015832 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15833 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15834 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015835 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015836 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015837 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015838 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15839 * Any other models that need this preset?
15840 */
15841 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015842 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15843 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015844 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15845 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15846 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15847 /* FIXME: the below seems conflict */
15848 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15849 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15850 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015851 {}
15852};
15853
Takashi Iwaia9111322011-05-02 11:30:18 +020015854static const struct alc_config_preset alc861_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015855 [ALC861_3ST] = {
15856 .mixers = { alc861_3ST_mixer },
15857 .init_verbs = { alc861_threestack_init_verbs },
15858 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15859 .dac_nids = alc861_dac_nids,
15860 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15861 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015862 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015863 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15864 .adc_nids = alc861_adc_nids,
15865 .input_mux = &alc861_capture_source,
15866 },
15867 [ALC861_3ST_DIG] = {
15868 .mixers = { alc861_base_mixer },
15869 .init_verbs = { alc861_threestack_init_verbs },
15870 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15871 .dac_nids = alc861_dac_nids,
15872 .dig_out_nid = ALC861_DIGOUT_NID,
15873 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15874 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015875 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015876 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15877 .adc_nids = alc861_adc_nids,
15878 .input_mux = &alc861_capture_source,
15879 },
15880 [ALC861_6ST_DIG] = {
15881 .mixers = { alc861_base_mixer },
15882 .init_verbs = { alc861_base_init_verbs },
15883 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15884 .dac_nids = alc861_dac_nids,
15885 .dig_out_nid = ALC861_DIGOUT_NID,
15886 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15887 .channel_mode = alc861_8ch_modes,
15888 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15889 .adc_nids = alc861_adc_nids,
15890 .input_mux = &alc861_capture_source,
15891 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015892 [ALC660_3ST] = {
15893 .mixers = { alc861_3ST_mixer },
15894 .init_verbs = { alc861_threestack_init_verbs },
15895 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15896 .dac_nids = alc660_dac_nids,
15897 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15898 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015899 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015900 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15901 .adc_nids = alc861_adc_nids,
15902 .input_mux = &alc861_capture_source,
15903 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015904 [ALC861_UNIWILL_M31] = {
15905 .mixers = { alc861_uniwill_m31_mixer },
15906 .init_verbs = { alc861_uniwill_m31_init_verbs },
15907 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15908 .dac_nids = alc861_dac_nids,
15909 .dig_out_nid = ALC861_DIGOUT_NID,
15910 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15911 .channel_mode = alc861_uniwill_m31_modes,
15912 .need_dac_fix = 1,
15913 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15914 .adc_nids = alc861_adc_nids,
15915 .input_mux = &alc861_capture_source,
15916 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015917 [ALC861_TOSHIBA] = {
15918 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015919 .init_verbs = { alc861_base_init_verbs,
15920 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015921 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15922 .dac_nids = alc861_dac_nids,
15923 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15924 .channel_mode = alc883_3ST_2ch_modes,
15925 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15926 .adc_nids = alc861_adc_nids,
15927 .input_mux = &alc861_capture_source,
15928 .unsol_event = alc861_toshiba_unsol_event,
15929 .init_hook = alc861_toshiba_automute,
15930 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015931 [ALC861_ASUS] = {
15932 .mixers = { alc861_asus_mixer },
15933 .init_verbs = { alc861_asus_init_verbs },
15934 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15935 .dac_nids = alc861_dac_nids,
15936 .dig_out_nid = ALC861_DIGOUT_NID,
15937 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15938 .channel_mode = alc861_asus_modes,
15939 .need_dac_fix = 1,
15940 .hp_nid = 0x06,
15941 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15942 .adc_nids = alc861_adc_nids,
15943 .input_mux = &alc861_capture_source,
15944 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015945 [ALC861_ASUS_LAPTOP] = {
15946 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15947 .init_verbs = { alc861_asus_init_verbs,
15948 alc861_asus_laptop_init_verbs },
15949 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15950 .dac_nids = alc861_dac_nids,
15951 .dig_out_nid = ALC861_DIGOUT_NID,
15952 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15953 .channel_mode = alc883_3ST_2ch_modes,
15954 .need_dac_fix = 1,
15955 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15956 .adc_nids = alc861_adc_nids,
15957 .input_mux = &alc861_capture_source,
15958 },
15959};
Kailang Yangdf694da2005-12-05 19:42:22 +010015960
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015961/* Pin config fixes */
15962enum {
15963 PINFIX_FSC_AMILO_PI1505,
15964};
15965
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015966static const struct alc_fixup alc861_fixups[] = {
15967 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015968 .type = ALC_FIXUP_PINS,
15969 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020015970 { 0x0b, 0x0221101f }, /* HP */
15971 { 0x0f, 0x90170310 }, /* speaker */
15972 { }
15973 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015974 },
15975};
15976
Takashi Iwaia9111322011-05-02 11:30:18 +020015977static const struct snd_pci_quirk alc861_fixup_tbl[] = {
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015978 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15979 {}
15980};
Kailang Yangdf694da2005-12-05 19:42:22 +010015981
15982static int patch_alc861(struct hda_codec *codec)
15983{
15984 struct alc_spec *spec;
15985 int board_config;
15986 int err;
15987
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015988 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015989 if (spec == NULL)
15990 return -ENOMEM;
15991
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015992 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015993
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020015994 spec->mixer_nid = 0x15;
15995
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015996 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15997 alc861_models,
15998 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015999
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016000 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016001 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16002 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016003 board_config = ALC861_AUTO;
16004 }
16005
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016006 if (board_config == ALC861_AUTO) {
16007 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
16008 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16009 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016010
Kailang Yangdf694da2005-12-05 19:42:22 +010016011 if (board_config == ALC861_AUTO) {
16012 /* automatic parse from the BIOS config */
16013 err = alc861_parse_auto_config(codec);
16014 if (err < 0) {
16015 alc_free(codec);
16016 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016017 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016018 printk(KERN_INFO
16019 "hda_codec: Cannot set up configuration "
16020 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016021 board_config = ALC861_3ST_DIG;
16022 }
16023 }
16024
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016025 err = snd_hda_attach_beep_device(codec, 0x23);
16026 if (err < 0) {
16027 alc_free(codec);
16028 return err;
16029 }
16030
Kailang Yangdf694da2005-12-05 19:42:22 +010016031 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016032 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016033
Kailang Yangdf694da2005-12-05 19:42:22 +010016034 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16035 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16036
Kailang Yangdf694da2005-12-05 19:42:22 +010016037 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16038 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16039
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016040 if (!spec->cap_mixer)
16041 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016042 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16043
Takashi Iwai2134ea42008-01-10 16:53:55 +010016044 spec->vmaster_nid = 0x03;
16045
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016046 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016047
Kailang Yangdf694da2005-12-05 19:42:22 +010016048 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016049 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016050 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016051#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016052 spec->power_hook = alc_power_eapd;
16053#endif
16054 }
16055#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016056 if (!spec->loopback.amplist)
16057 spec->loopback.amplist = alc861_loopbacks;
16058#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016059
Kailang Yangdf694da2005-12-05 19:42:22 +010016060 return 0;
16061}
16062
16063/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016064 * ALC861-VD support
16065 *
16066 * Based on ALC882
16067 *
16068 * In addition, an independent DAC
16069 */
16070#define ALC861VD_DIGOUT_NID 0x06
16071
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016072static const hda_nid_t alc861vd_dac_nids[4] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016073 /* front, surr, clfe, side surr */
16074 0x02, 0x03, 0x04, 0x05
16075};
16076
16077/* dac_nids for ALC660vd are in a different order - according to
16078 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016079 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016080 * of ALC660vd codecs, but for now there is only 3stack mixer
16081 * - and it is the same as in 861vd.
16082 * adc_nids in ALC660vd are (is) the same as in 861vd
16083 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016084static const hda_nid_t alc660vd_dac_nids[3] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016085 /* front, rear, clfe, rear_surr */
16086 0x02, 0x04, 0x03
16087};
16088
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016089static const hda_nid_t alc861vd_adc_nids[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016090 /* ADC0 */
16091 0x09,
16092};
16093
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016094static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010016095
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016096/* input MUX */
16097/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020016098static const struct hda_input_mux alc861vd_capture_source = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016099 .num_items = 4,
16100 .items = {
16101 { "Mic", 0x0 },
16102 { "Front Mic", 0x1 },
16103 { "Line", 0x2 },
16104 { "CD", 0x4 },
16105 },
16106};
16107
Takashi Iwaia9111322011-05-02 11:30:18 +020016108static const struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016109 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016110 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010016111 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010016112 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016113 },
16114};
16115
Takashi Iwaia9111322011-05-02 11:30:18 +020016116static const struct hda_input_mux alc861vd_hp_capture_source = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016117 .num_items = 2,
16118 .items = {
16119 { "Front Mic", 0x0 },
16120 { "ATAPI Mic", 0x1 },
16121 },
16122};
16123
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016124/*
16125 * 2ch mode
16126 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016127static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016128 { 2, NULL }
16129};
16130
16131/*
16132 * 6ch mode
16133 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016134static const struct hda_verb alc861vd_6stack_ch6_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016135 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16136 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16137 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16138 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16139 { } /* end */
16140};
16141
16142/*
16143 * 8ch mode
16144 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016145static const struct hda_verb alc861vd_6stack_ch8_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016146 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16147 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16148 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16149 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16150 { } /* end */
16151};
16152
Takashi Iwaia9111322011-05-02 11:30:18 +020016153static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016154 { 6, alc861vd_6stack_ch6_init },
16155 { 8, alc861vd_6stack_ch8_init },
16156};
16157
Takashi Iwaia9111322011-05-02 11:30:18 +020016158static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016159 {
16160 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16161 .name = "Channel Mode",
16162 .info = alc_ch_mode_info,
16163 .get = alc_ch_mode_get,
16164 .put = alc_ch_mode_put,
16165 },
16166 { } /* end */
16167};
16168
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016169/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16170 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16171 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016172static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016173 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16174 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16175
16176 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16177 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16178
16179 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16180 HDA_OUTPUT),
16181 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16182 HDA_OUTPUT),
16183 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16184 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16185
16186 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16187 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16188
16189 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16190
David Henningsson5f99f862011-01-04 15:24:24 +010016191 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016192 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16193 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16194
David Henningsson5f99f862011-01-04 15:24:24 +010016195 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016196 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16197 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16198
16199 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16200 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16201
16202 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16203 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16204
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016205 { } /* end */
16206};
16207
Takashi Iwaia9111322011-05-02 11:30:18 +020016208static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016209 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16210 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16211
16212 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16213
David Henningsson5f99f862011-01-04 15:24:24 +010016214 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016215 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16216 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16217
David Henningsson5f99f862011-01-04 15:24:24 +010016218 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016219 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16220 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16221
16222 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16223 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16224
16225 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16226 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16227
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016228 { } /* end */
16229};
16230
Takashi Iwaia9111322011-05-02 11:30:18 +020016231static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016232 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16233 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16234 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16235
16236 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16237
David Henningsson5f99f862011-01-04 15:24:24 +010016238 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016239 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16240 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16241
David Henningsson5f99f862011-01-04 15:24:24 +010016242 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016243 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16244 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16245
16246 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16247 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16248
16249 { } /* end */
16250};
16251
Tobin Davisb419f342008-03-07 11:57:51 +010016252/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016253 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016254 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016255static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016256 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16257 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016258 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16259 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016260 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016261 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16262 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016263 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016264 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16265 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016266 { } /* end */
16267};
16268
Kailang Yangd1a991a2007-08-15 16:21:59 +020016269/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16270 * Front Mic=0x18, ATAPI Mic = 0x19,
16271 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016272static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016273 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16274 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16275 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16276 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16277 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16278 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16279 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16280 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016281
Kailang Yangd1a991a2007-08-15 16:21:59 +020016282 { } /* end */
16283};
16284
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016285/*
16286 * generic initialization of ADC, input mixers and output mixers
16287 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016288static const struct hda_verb alc861vd_volume_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016289 /*
16290 * Unmute ADC0 and set the default input to mic-in
16291 */
16292 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16293 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16294
16295 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16296 * the analog-loopback mixer widget
16297 */
16298 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016299 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16300 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16301 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16302 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16303 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016304
16305 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016306 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16307 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16308 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016309 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016310
16311 /*
16312 * Set up output mixers (0x02 - 0x05)
16313 */
16314 /* set vol=0 to output mixers */
16315 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16316 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16317 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16318 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16319
16320 /* set up input amps for analog loopback */
16321 /* Amp Indices: DAC = 0, mixer = 1 */
16322 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16323 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16324 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16325 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16326 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16327 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16328 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16329 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16330
16331 { }
16332};
16333
16334/*
16335 * 3-stack pin configuration:
16336 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16337 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016338static const struct hda_verb alc861vd_3stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016339 /*
16340 * Set pin mode and muting
16341 */
16342 /* set front pin widgets 0x14 for output */
16343 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16344 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16345 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16346
16347 /* Mic (rear) pin: input vref at 80% */
16348 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16349 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16350 /* Front Mic pin: input vref at 80% */
16351 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16352 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16353 /* Line In pin: input */
16354 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16355 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16356 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16357 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16358 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16359 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16360 /* CD pin widget for input */
16361 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16362
16363 { }
16364};
16365
16366/*
16367 * 6-stack pin configuration:
16368 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016369static const struct hda_verb alc861vd_6stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016370 /*
16371 * Set pin mode and muting
16372 */
16373 /* set front pin widgets 0x14 for output */
16374 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16375 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16376 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16377
16378 /* Rear Pin: output 1 (0x0d) */
16379 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16380 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16381 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16382 /* CLFE Pin: output 2 (0x0e) */
16383 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16384 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16385 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16386 /* Side Pin: output 3 (0x0f) */
16387 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16388 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16389 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16390
16391 /* Mic (rear) pin: input vref at 80% */
16392 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16393 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16394 /* Front Mic pin: input vref at 80% */
16395 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16396 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16397 /* Line In pin: input */
16398 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16399 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16400 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16401 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16402 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16403 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16404 /* CD pin widget for input */
16405 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16406
16407 { }
16408};
16409
Takashi Iwaia9111322011-05-02 11:30:18 +020016410static const struct hda_verb alc861vd_eapd_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016411 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16412 { }
16413};
16414
Takashi Iwaia9111322011-05-02 11:30:18 +020016415static const struct hda_verb alc660vd_eapd_verbs[] = {
Kailang Yangf9423e72008-05-27 12:32:25 +020016416 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16417 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16418 { }
16419};
16420
Takashi Iwaia9111322011-05-02 11:30:18 +020016421static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016422 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16423 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16424 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16425 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016426 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016427 {}
16428};
16429
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016430static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016431{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016432 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016433 spec->autocfg.hp_pins[0] = 0x1b;
16434 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016435 spec->automute = 1;
16436 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016437}
16438
16439static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16440{
Takashi Iwaid922b512011-04-28 12:18:53 +020016441 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016442 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016443}
16444
16445static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16446 unsigned int res)
16447{
16448 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016449 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016450 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016451 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016452 default:
Takashi Iwaid922b512011-04-28 12:18:53 +020016453 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016454 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016455 }
16456}
16457
Takashi Iwaia9111322011-05-02 11:30:18 +020016458static const struct hda_verb alc861vd_dallas_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020016459 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16460 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16461 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16462 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16463
16464 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16465 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16466 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16467 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16468 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16469 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16470 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16471 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016472
Kailang Yang272a5272007-05-14 11:00:38 +020016473 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16474 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16475 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16476 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16477 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16478 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16479 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16480 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16481
16482 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16483 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16484 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16485 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16486 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16487 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16488 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16489 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16490
16491 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16492 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16493 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16494 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16495
16496 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016497 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016498 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16499
16500 { } /* end */
16501};
16502
16503/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016504static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016505{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016506 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016507
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016508 spec->autocfg.hp_pins[0] = 0x15;
16509 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016510 spec->automute = 1;
16511 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +020016512}
16513
Takashi Iwaicb53c622007-08-10 17:21:45 +020016514#ifdef CONFIG_SND_HDA_POWER_SAVE
16515#define alc861vd_loopbacks alc880_loopbacks
16516#endif
16517
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016518/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016519#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16520#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16521#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16522#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16523
16524/*
16525 * configuration and preset
16526 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016527static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016528 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016529 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016530 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016531 [ALC861VD_3ST] = "3stack",
16532 [ALC861VD_3ST_DIG] = "3stack-digout",
16533 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016534 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016535 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016536 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016537 [ALC861VD_AUTO] = "auto",
16538};
16539
Takashi Iwaia9111322011-05-02 11:30:18 +020016540static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016541 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16542 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016543 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016544 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016545 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016546 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016547 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016548 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016549 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016550 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016551 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016552 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016553 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016554 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016555 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016556 {}
16557};
16558
Takashi Iwaia9111322011-05-02 11:30:18 +020016559static const struct alc_config_preset alc861vd_presets[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016560 [ALC660VD_3ST] = {
16561 .mixers = { alc861vd_3st_mixer },
16562 .init_verbs = { alc861vd_volume_init_verbs,
16563 alc861vd_3stack_init_verbs },
16564 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16565 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016566 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16567 .channel_mode = alc861vd_3stack_2ch_modes,
16568 .input_mux = &alc861vd_capture_source,
16569 },
Mike Crash6963f842007-06-25 12:12:51 +020016570 [ALC660VD_3ST_DIG] = {
16571 .mixers = { alc861vd_3st_mixer },
16572 .init_verbs = { alc861vd_volume_init_verbs,
16573 alc861vd_3stack_init_verbs },
16574 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16575 .dac_nids = alc660vd_dac_nids,
16576 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016577 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16578 .channel_mode = alc861vd_3stack_2ch_modes,
16579 .input_mux = &alc861vd_capture_source,
16580 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016581 [ALC861VD_3ST] = {
16582 .mixers = { alc861vd_3st_mixer },
16583 .init_verbs = { alc861vd_volume_init_verbs,
16584 alc861vd_3stack_init_verbs },
16585 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16586 .dac_nids = alc861vd_dac_nids,
16587 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16588 .channel_mode = alc861vd_3stack_2ch_modes,
16589 .input_mux = &alc861vd_capture_source,
16590 },
16591 [ALC861VD_3ST_DIG] = {
16592 .mixers = { alc861vd_3st_mixer },
16593 .init_verbs = { alc861vd_volume_init_verbs,
16594 alc861vd_3stack_init_verbs },
16595 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16596 .dac_nids = alc861vd_dac_nids,
16597 .dig_out_nid = ALC861VD_DIGOUT_NID,
16598 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16599 .channel_mode = alc861vd_3stack_2ch_modes,
16600 .input_mux = &alc861vd_capture_source,
16601 },
16602 [ALC861VD_6ST_DIG] = {
16603 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16604 .init_verbs = { alc861vd_volume_init_verbs,
16605 alc861vd_6stack_init_verbs },
16606 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16607 .dac_nids = alc861vd_dac_nids,
16608 .dig_out_nid = ALC861VD_DIGOUT_NID,
16609 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16610 .channel_mode = alc861vd_6stack_modes,
16611 .input_mux = &alc861vd_capture_source,
16612 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016613 [ALC861VD_LENOVO] = {
16614 .mixers = { alc861vd_lenovo_mixer },
16615 .init_verbs = { alc861vd_volume_init_verbs,
16616 alc861vd_3stack_init_verbs,
16617 alc861vd_eapd_verbs,
16618 alc861vd_lenovo_unsol_verbs },
16619 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16620 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016621 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16622 .channel_mode = alc861vd_3stack_2ch_modes,
16623 .input_mux = &alc861vd_capture_source,
16624 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016625 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016626 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016627 },
Kailang Yang272a5272007-05-14 11:00:38 +020016628 [ALC861VD_DALLAS] = {
16629 .mixers = { alc861vd_dallas_mixer },
16630 .init_verbs = { alc861vd_dallas_verbs },
16631 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16632 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016633 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16634 .channel_mode = alc861vd_3stack_2ch_modes,
16635 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020016636 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016637 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020016638 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016639 },
16640 [ALC861VD_HP] = {
16641 .mixers = { alc861vd_hp_mixer },
16642 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16643 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16644 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016645 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016646 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16647 .channel_mode = alc861vd_3stack_2ch_modes,
16648 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020016649 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016650 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020016651 .init_hook = alc_hp_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020016652 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016653 [ALC660VD_ASUS_V1S] = {
16654 .mixers = { alc861vd_lenovo_mixer },
16655 .init_verbs = { alc861vd_volume_init_verbs,
16656 alc861vd_3stack_init_verbs,
16657 alc861vd_eapd_verbs,
16658 alc861vd_lenovo_unsol_verbs },
16659 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16660 .dac_nids = alc660vd_dac_nids,
16661 .dig_out_nid = ALC861VD_DIGOUT_NID,
16662 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16663 .channel_mode = alc861vd_3stack_2ch_modes,
16664 .input_mux = &alc861vd_capture_source,
16665 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016666 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016667 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016668 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016669};
16670
16671/*
16672 * BIOS auto configuration
16673 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016674static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16675 const struct auto_pin_cfg *cfg)
16676{
Herton Ronaldo Krzesinski71675942010-11-25 00:08:01 -020016677 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016678}
16679
16680
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020016681#define alc861vd_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020016682#define alc861vd_auto_init_input_src alc882_auto_init_input_src
16683
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016684#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16685#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16686
16687/* add playback controls from the parsed DAC table */
Takashi Iwai569ed342011-01-19 10:14:46 +010016688/* Based on ALC880 version. But ALC861VD has separate,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016689 * different NIDs for mute/unmute switch and volume control */
16690static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16691 const struct auto_pin_cfg *cfg)
16692{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016693 hda_nid_t nid_v, nid_s;
Takashi Iwaice764ab2011-04-27 16:35:23 +020016694 int i, err, noutputs;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016695
Takashi Iwaice764ab2011-04-27 16:35:23 +020016696 noutputs = cfg->line_outs;
16697 if (spec->multi_ios > 0)
16698 noutputs += spec->multi_ios;
16699
16700 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020016701 const char *name;
16702 int index;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016703 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016704 continue;
16705 nid_v = alc861vd_idx_to_mixer_vol(
16706 alc880_dac_to_idx(
16707 spec->multiout.dac_nids[i]));
16708 nid_s = alc861vd_idx_to_mixer_switch(
16709 alc880_dac_to_idx(
16710 spec->multiout.dac_nids[i]));
16711
Takashi Iwai6843ca12011-06-24 11:03:58 +020016712 name = alc_get_line_out_pfx(spec, i, true, &index);
16713 if (!name) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016714 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016715 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16716 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016717 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16718 HDA_OUTPUT));
16719 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016720 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016721 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16722 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016723 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16724 HDA_OUTPUT));
16725 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016726 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016727 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16728 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016729 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16730 HDA_INPUT));
16731 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016732 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016733 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16734 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016735 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16736 HDA_INPUT));
16737 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016738 return err;
16739 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016740 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
David Henningsson5a882642011-03-23 08:35:07 +010016741 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016742 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16743 HDA_OUTPUT));
16744 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016745 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016746 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
David Henningsson5a882642011-03-23 08:35:07 +010016747 name, index,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016748 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016749 HDA_INPUT));
16750 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016751 return err;
16752 }
16753 }
16754 return 0;
16755}
16756
16757/* add playback controls for speaker and HP outputs */
16758/* Based on ALC880 version. But ALC861VD has separate,
16759 * different NIDs for mute/unmute switch and volume control */
16760static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16761 hda_nid_t pin, const char *pfx)
16762{
16763 hda_nid_t nid_v, nid_s;
16764 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016765
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016766 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016767 return 0;
16768
16769 if (alc880_is_fixed_pin(pin)) {
16770 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16771 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016772 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016773 spec->multiout.hp_nid = nid_v;
16774 else
16775 spec->multiout.extra_out_nid[0] = nid_v;
16776 /* control HP volume/switch on the output mixer amp */
16777 nid_v = alc861vd_idx_to_mixer_vol(
16778 alc880_fixed_pin_idx(pin));
16779 nid_s = alc861vd_idx_to_mixer_switch(
16780 alc880_fixed_pin_idx(pin));
16781
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016782 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016783 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16784 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016785 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016786 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016787 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16788 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016789 return err;
16790 } else if (alc880_is_multi_pin(pin)) {
16791 /* set manual connection */
16792 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016793 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016794 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16795 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016796 return err;
16797 }
16798 return 0;
16799}
16800
16801/* parse the BIOS configuration and set up the alc_spec
16802 * return 1 if successful, 0 if the proper config is not found,
16803 * or a negative error code
16804 * Based on ALC880 version - had to change it to override
16805 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16806static int alc861vd_parse_auto_config(struct hda_codec *codec)
16807{
16808 struct alc_spec *spec = codec->spec;
16809 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016810 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016811
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016812 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16813 alc861vd_ignore);
16814 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016815 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016816 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016817 return 0; /* can't find valid BIOS pin config */
16818
Takashi Iwai343a04b2011-07-06 14:28:39 +020016819 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016820 if (err < 0)
16821 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020016822 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020016823 if (err < 0)
16824 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016825 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16826 if (err < 0)
16827 return err;
16828 err = alc861vd_auto_create_extra_out(spec,
16829 spec->autocfg.speaker_pins[0],
16830 "Speaker");
16831 if (err < 0)
16832 return err;
16833 err = alc861vd_auto_create_extra_out(spec,
16834 spec->autocfg.hp_pins[0],
16835 "Headphone");
16836 if (err < 0)
16837 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016838 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016839 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016840 return err;
16841
16842 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16843
Takashi Iwai757899a2010-07-30 10:48:14 +020016844 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016845
Takashi Iwai603c4012008-07-30 15:01:44 +020016846 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016847 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016848
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016849 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016850 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016851
Takashi Iwai776e1842007-08-29 15:07:11 +020016852 err = alc_auto_add_mic_boost(codec);
16853 if (err < 0)
16854 return err;
16855
Kailang Yang6227cdc2010-02-25 08:36:52 +010016856 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016857
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016858 return 1;
16859}
16860
16861/* additional initialization for auto-configuration model */
16862static void alc861vd_auto_init(struct hda_codec *codec)
16863{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016864 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020016865 alc_auto_init_multi_out(codec);
16866 alc_auto_init_extra_out(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016867 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020016868 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016869 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016870 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016871 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016872}
16873
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016874enum {
16875 ALC660VD_FIX_ASUS_GPIO1
16876};
16877
16878/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016879static const struct alc_fixup alc861vd_fixups[] = {
16880 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016881 .type = ALC_FIXUP_VERBS,
16882 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020016883 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16884 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16885 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16886 { }
16887 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016888 },
16889};
16890
Takashi Iwaia9111322011-05-02 11:30:18 +020016891static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016892 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16893 {}
16894};
16895
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016896static int patch_alc861vd(struct hda_codec *codec)
16897{
16898 struct alc_spec *spec;
16899 int err, board_config;
16900
16901 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16902 if (spec == NULL)
16903 return -ENOMEM;
16904
16905 codec->spec = spec;
16906
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020016907 spec->mixer_nid = 0x0b;
16908
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016909 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16910 alc861vd_models,
16911 alc861vd_cfg_tbl);
16912
16913 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016914 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16915 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016916 board_config = ALC861VD_AUTO;
16917 }
16918
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016919 if (board_config == ALC861VD_AUTO) {
16920 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
16921 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16922 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016923
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016924 if (board_config == ALC861VD_AUTO) {
16925 /* automatic parse from the BIOS config */
16926 err = alc861vd_parse_auto_config(codec);
16927 if (err < 0) {
16928 alc_free(codec);
16929 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016930 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016931 printk(KERN_INFO
16932 "hda_codec: Cannot set up configuration "
16933 "from BIOS. Using base mode...\n");
16934 board_config = ALC861VD_3ST;
16935 }
16936 }
16937
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016938 err = snd_hda_attach_beep_device(codec, 0x23);
16939 if (err < 0) {
16940 alc_free(codec);
16941 return err;
16942 }
16943
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016944 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016945 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016946
Kailang Yang2f893282008-05-27 12:14:47 +020016947 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016948 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016949 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016950 }
16951
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016952 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
16953 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
16954
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016955 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
16956 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
16957
Takashi Iwaidd704692009-08-11 08:45:11 +020016958 if (!spec->adc_nids) {
16959 spec->adc_nids = alc861vd_adc_nids;
16960 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
16961 }
16962 if (!spec->capsrc_nids)
16963 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016964
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016965 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016966 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016967
Takashi Iwai2134ea42008-01-10 16:53:55 +010016968 spec->vmaster_nid = 0x02;
16969
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016970 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016971
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016972 codec->patch_ops = alc_patch_ops;
16973
16974 if (board_config == ALC861VD_AUTO)
16975 spec->init_hook = alc861vd_auto_init;
Takashi Iwai1c7161532011-04-07 10:37:16 +020016976 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016977#ifdef CONFIG_SND_HDA_POWER_SAVE
16978 if (!spec->loopback.amplist)
16979 spec->loopback.amplist = alc861vd_loopbacks;
16980#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016981
16982 return 0;
16983}
16984
16985/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016986 * ALC662 support
16987 *
16988 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16989 * configuration. Each pin widget can choose any input DACs and a mixer.
16990 * Each ADC is connected from a mixer of all inputs. This makes possible
16991 * 6-channel independent captures.
16992 *
16993 * In addition, an independent DAC for the multi-playback (not used in this
16994 * driver yet).
16995 */
16996#define ALC662_DIGOUT_NID 0x06
16997#define ALC662_DIGIN_NID 0x0a
16998
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016999static const hda_nid_t alc662_dac_nids[3] = {
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080017000 /* front, rear, clfe */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017001 0x02, 0x03, 0x04
17002};
17003
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017004static const hda_nid_t alc272_dac_nids[2] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017005 0x02, 0x03
17006};
17007
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017008static const hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017009 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017010 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017011};
Takashi Iwaie1406342008-02-11 18:32:32 +010017012
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017013static const hda_nid_t alc272_adc_nids[1] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017014 /* ADC1-2 */
17015 0x08,
17016};
17017
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017018static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
17019static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017020
Takashi Iwaie1406342008-02-11 18:32:32 +010017021
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017022/* input MUX */
17023/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020017024static const struct hda_input_mux alc662_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017025 .num_items = 4,
17026 .items = {
17027 { "Mic", 0x0 },
17028 { "Front Mic", 0x1 },
17029 { "Line", 0x2 },
17030 { "CD", 0x4 },
17031 },
17032};
17033
Takashi Iwaia9111322011-05-02 11:30:18 +020017034static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017035 .num_items = 2,
17036 .items = {
17037 { "Mic", 0x1 },
17038 { "Line", 0x2 },
17039 },
17040};
Kailang Yang291702f2007-10-16 14:28:03 +020017041
Takashi Iwaia9111322011-05-02 11:30:18 +020017042static const struct hda_input_mux alc663_capture_source = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017043 .num_items = 3,
17044 .items = {
17045 { "Mic", 0x0 },
17046 { "Front Mic", 0x1 },
17047 { "Line", 0x2 },
17048 },
17049};
17050
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017051#if 0 /* set to 1 for testing other input sources below */
Takashi Iwaia9111322011-05-02 11:30:18 +020017052static const struct hda_input_mux alc272_nc10_capture_source = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020017053 .num_items = 16,
17054 .items = {
17055 { "Autoselect Mic", 0x0 },
17056 { "Internal Mic", 0x1 },
17057 { "In-0x02", 0x2 },
17058 { "In-0x03", 0x3 },
17059 { "In-0x04", 0x4 },
17060 { "In-0x05", 0x5 },
17061 { "In-0x06", 0x6 },
17062 { "In-0x07", 0x7 },
17063 { "In-0x08", 0x8 },
17064 { "In-0x09", 0x9 },
17065 { "In-0x0a", 0x0a },
17066 { "In-0x0b", 0x0b },
17067 { "In-0x0c", 0x0c },
17068 { "In-0x0d", 0x0d },
17069 { "In-0x0e", 0x0e },
17070 { "In-0x0f", 0x0f },
17071 },
17072};
17073#endif
17074
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017075/*
17076 * 2ch mode
17077 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017078static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017079 { 2, NULL }
17080};
17081
17082/*
17083 * 2ch mode
17084 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017085static const struct hda_verb alc662_3ST_ch2_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017086 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17087 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17088 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17089 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17090 { } /* end */
17091};
17092
17093/*
17094 * 6ch mode
17095 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017096static const struct hda_verb alc662_3ST_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017097 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17098 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17099 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17100 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17101 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17102 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17103 { } /* end */
17104};
17105
Takashi Iwaia9111322011-05-02 11:30:18 +020017106static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017107 { 2, alc662_3ST_ch2_init },
17108 { 6, alc662_3ST_ch6_init },
17109};
17110
17111/*
17112 * 2ch mode
17113 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017114static const struct hda_verb alc662_sixstack_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017115 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17116 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17117 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17118 { } /* end */
17119};
17120
17121/*
17122 * 6ch mode
17123 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017124static const struct hda_verb alc662_sixstack_ch8_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017125 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17126 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17127 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17128 { } /* end */
17129};
17130
Takashi Iwaia9111322011-05-02 11:30:18 +020017131static const struct hda_channel_mode alc662_5stack_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017132 { 2, alc662_sixstack_ch6_init },
17133 { 6, alc662_sixstack_ch8_init },
17134};
17135
17136/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17137 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17138 */
17139
Takashi Iwaia9111322011-05-02 11:30:18 +020017140static const struct snd_kcontrol_new alc662_base_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017141 /* output mixer control */
17142 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017143 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017144 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017145 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017146 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17147 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017148 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17149 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017150 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17151
17152 /*Input mixer control */
17153 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17154 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17155 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17156 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17157 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17158 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17159 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17160 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017161 { } /* end */
17162};
17163
Takashi Iwaia9111322011-05-02 11:30:18 +020017164static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017165 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017166 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017167 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17168 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17169 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17170 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17171 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17172 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17173 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17174 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17175 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017176 { } /* end */
17177};
17178
Takashi Iwaia9111322011-05-02 11:30:18 +020017179static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017180 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017181 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017182 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017183 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017184 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17185 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017186 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17187 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017188 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17189 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17190 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17191 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17192 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17193 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17194 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17195 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17196 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017197 { } /* end */
17198};
17199
Takashi Iwaia9111322011-05-02 11:30:18 +020017200static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017201 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17202 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017203 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17204 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017205 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17206 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17207 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17208 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17209 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017210 { } /* end */
17211};
17212
Takashi Iwaia9111322011-05-02 11:30:18 +020017213static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017214 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17215 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017216
David Henningsson5f99f862011-01-04 15:24:24 +010017217 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017218 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017220
David Henningsson5f99f862011-01-04 15:24:24 +010017221 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017222 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17223 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017224 { } /* end */
17225};
17226
Takashi Iwaia9111322011-05-02 11:30:18 +020017227static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017228 ALC262_HIPPO_MASTER_SWITCH,
17229 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017230 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017231 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17232 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017233 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17234 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17235 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17236 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17237 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17238 { } /* end */
17239};
17240
Takashi Iwaia9111322011-05-02 11:30:18 +020017241static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017242 .ops = &snd_hda_bind_vol,
17243 .values = {
17244 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17245 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17246 0
17247 },
17248};
17249
Takashi Iwaia9111322011-05-02 11:30:18 +020017250static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017251 .ops = &snd_hda_bind_sw,
17252 .values = {
17253 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17254 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17255 0
17256 },
17257};
17258
Takashi Iwaia9111322011-05-02 11:30:18 +020017259static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017260 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17261 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17262 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17263 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17264 { } /* end */
17265};
17266
Takashi Iwaia9111322011-05-02 11:30:18 +020017267static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017268 .ops = &snd_hda_bind_sw,
17269 .values = {
17270 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17271 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17272 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17273 0
17274 },
17275};
17276
Takashi Iwaia9111322011-05-02 11:30:18 +020017277static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017278 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17279 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17280 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17281 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17282 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17283 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17284
17285 { } /* end */
17286};
17287
Takashi Iwaia9111322011-05-02 11:30:18 +020017288static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017289 .ops = &snd_hda_bind_sw,
17290 .values = {
17291 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17292 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17293 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17294 0
17295 },
17296};
17297
Takashi Iwaia9111322011-05-02 11:30:18 +020017298static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017299 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17300 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17301 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17302 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17303 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17304 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17305 { } /* end */
17306};
17307
Takashi Iwaia9111322011-05-02 11:30:18 +020017308static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017309 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17310 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017311 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17312 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17313 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17314 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17315 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17316 { } /* end */
17317};
17318
Takashi Iwaia9111322011-05-02 11:30:18 +020017319static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017320 .ops = &snd_hda_bind_vol,
17321 .values = {
17322 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17323 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17324 0
17325 },
17326};
17327
Takashi Iwaia9111322011-05-02 11:30:18 +020017328static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017329 .ops = &snd_hda_bind_sw,
17330 .values = {
17331 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17332 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17333 0
17334 },
17335};
17336
Takashi Iwaia9111322011-05-02 11:30:18 +020017337static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017338 HDA_BIND_VOL("Master Playback Volume",
17339 &alc663_asus_two_bind_master_vol),
17340 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17341 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017342 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17343 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17344 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017345 { } /* end */
17346};
17347
Takashi Iwaia9111322011-05-02 11:30:18 +020017348static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017349 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17350 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17351 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17352 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17353 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17354 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017355 { } /* end */
17356};
17357
Takashi Iwaia9111322011-05-02 11:30:18 +020017358static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017359 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17360 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17361 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17362 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17363 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17364
17365 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17366 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017367 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17368 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017369 { } /* end */
17370};
17371
Takashi Iwaia9111322011-05-02 11:30:18 +020017372static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017373 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17374 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17375 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17376
17377 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17378 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017379 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17380 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017381 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17382 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17383 { } /* end */
17384};
17385
Takashi Iwaia9111322011-05-02 11:30:18 +020017386static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017387 .ops = &snd_hda_bind_sw,
17388 .values = {
17389 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17390 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17391 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17392 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17393 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17394 0
17395 },
17396};
17397
Takashi Iwaia9111322011-05-02 11:30:18 +020017398static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017399 .ops = &snd_hda_bind_sw,
17400 .values = {
17401 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17402 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17403 0
17404 },
17405};
17406
Takashi Iwaia9111322011-05-02 11:30:18 +020017407static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017408 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17409 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17410 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17411 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17412 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17413 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17414 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17415 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17416 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17417 { } /* end */
17418};
17419
Takashi Iwaia9111322011-05-02 11:30:18 +020017420static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017421 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17422 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17423 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17424 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17425 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17426 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17427 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17428 { } /* end */
17429};
17430
17431
Takashi Iwaia9111322011-05-02 11:30:18 +020017432static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017433 {
17434 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17435 .name = "Channel Mode",
17436 .info = alc_ch_mode_info,
17437 .get = alc_ch_mode_get,
17438 .put = alc_ch_mode_put,
17439 },
17440 { } /* end */
17441};
17442
Takashi Iwaia9111322011-05-02 11:30:18 +020017443static const struct hda_verb alc662_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017444 /* ADC: mute amp left and right */
17445 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17446 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017447
Kailang Yangb60dd392007-09-20 12:50:29 +020017448 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17449 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17450 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17451 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17452 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17453 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017454
17455 /* Front Pin: output 0 (0x0c) */
17456 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17457 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17458
17459 /* Rear Pin: output 1 (0x0d) */
17460 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17461 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17462
17463 /* CLFE Pin: output 2 (0x0e) */
17464 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17465 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17466
17467 /* Mic (rear) pin: input vref at 80% */
17468 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17469 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17470 /* Front Mic pin: input vref at 80% */
17471 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17472 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17473 /* Line In pin: input */
17474 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17475 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17476 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17477 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17478 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17479 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17480 /* CD pin widget for input */
17481 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17482
17483 /* FIXME: use matrix-type input source selection */
17484 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17485 /* Input mixer */
17486 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017487 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017488
Takashi Iwaia7f23712011-04-07 10:24:23 +020017489 { }
17490};
17491
Takashi Iwaia9111322011-05-02 11:30:18 +020017492static const struct hda_verb alc662_eapd_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017493 /* always trun on EAPD */
17494 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17495 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017496 { }
17497};
17498
Takashi Iwaia9111322011-05-02 11:30:18 +020017499static const struct hda_verb alc662_sue_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017500 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17501 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017502 {}
17503};
17504
Takashi Iwaia9111322011-05-02 11:30:18 +020017505static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020017506 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17507 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17508 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017509};
17510
Kailang Yang8c427222008-01-10 13:03:59 +010017511/* Set Unsolicited Event*/
Takashi Iwaia9111322011-05-02 11:30:18 +020017512static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010017513 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17514 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17515 {}
17516};
17517
Takashi Iwaia9111322011-05-02 11:30:18 +020017518static const struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017519 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17520 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017521 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17522 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017523 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17524 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17525 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017526 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17527 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17528 {}
17529};
17530
Takashi Iwaia9111322011-05-02 11:30:18 +020017531static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017532 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17533 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17534 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17535 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17536 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17537 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17538 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17539 {}
17540};
17541
Takashi Iwaia9111322011-05-02 11:30:18 +020017542static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017543 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17544 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17545 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17546 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17547 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17548 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17549 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17550 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17551 {}
17552};
17553
Takashi Iwaia9111322011-05-02 11:30:18 +020017554static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017555 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17556 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17557 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17558 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17559 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17560 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17561 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17562 {}
17563};
17564
Takashi Iwaia9111322011-05-02 11:30:18 +020017565static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017566 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17567 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17568 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17569 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17570 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17571 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17572 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17573 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17574 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17575 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17576 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17577 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17578 {}
17579};
17580
Takashi Iwaia9111322011-05-02 11:30:18 +020017581static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017582 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17583 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17584 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17585 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17586 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17587 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17588 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17589 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17590 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17591 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17592 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17593 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17594 {}
17595};
17596
Takashi Iwaia9111322011-05-02 11:30:18 +020017597static const struct hda_verb alc663_g71v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017598 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17599 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17600 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17601
17602 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17603 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17604 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17605
17606 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17607 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17608 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17609 {}
17610};
17611
Takashi Iwaia9111322011-05-02 11:30:18 +020017612static const struct hda_verb alc663_g50v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017613 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17614 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17615 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17616
17617 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17618 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17619 {}
17620};
17621
Takashi Iwaia9111322011-05-02 11:30:18 +020017622static const struct hda_verb alc662_ecs_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017623 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17624 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17625 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17626 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17627 {}
17628};
17629
Takashi Iwaia9111322011-05-02 11:30:18 +020017630static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017631 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17632 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17633 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17634 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17635 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17636 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17637 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17638 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17639 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17640 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17641 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17642 {}
17643};
17644
Takashi Iwaia9111322011-05-02 11:30:18 +020017645static const struct hda_verb alc272_dell_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017646 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17647 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17648 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17649 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17650 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17651 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17652 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17653 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17654 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17655 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17656 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17657 {}
17658};
17659
Takashi Iwaia9111322011-05-02 11:30:18 +020017660static const struct hda_verb alc663_mode7_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017661 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17662 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17663 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17664 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17665 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17666 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17667 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17668 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17669 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17670 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17671 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17672 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17673 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17674 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17675 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17676 {}
17677};
17678
Takashi Iwaia9111322011-05-02 11:30:18 +020017679static const struct hda_verb alc663_mode8_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017680 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17681 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17682 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17683 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17684 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17685 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17686 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17687 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17688 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17689 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17690 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17691 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17692 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17693 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17694 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17695 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17696 {}
17697};
17698
Takashi Iwaia9111322011-05-02 11:30:18 +020017699static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017700 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17701 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17702 { } /* end */
17703};
17704
Takashi Iwaia9111322011-05-02 11:30:18 +020017705static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017706 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17707 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17708 { } /* end */
17709};
17710
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017711static void alc662_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017712{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017713 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017714
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017715 spec->autocfg.hp_pins[0] = 0x1b;
17716 spec->autocfg.line_out_pins[0] = 0x14;
17717 spec->autocfg.speaker_pins[0] = 0x15;
17718 spec->automute = 1;
17719 spec->detect_line = 1;
17720 spec->automute_lines = 1;
17721 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017722}
17723
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017724static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017725{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017726 struct alc_spec *spec = codec->spec;
17727
17728 alc262_hippo1_setup(codec);
17729 spec->ext_mic.pin = 0x18;
17730 spec->ext_mic.mux_idx = 0;
17731 spec->int_mic.pin = 0x19;
17732 spec->int_mic.mux_idx = 1;
17733 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017734}
17735
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017736static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017737{
Takashi Iwai42171c12009-05-08 14:11:43 +020017738 struct alc_spec *spec = codec->spec;
17739
17740 spec->autocfg.hp_pins[0] = 0x14;
17741 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaie9427962011-04-28 15:46:07 +020017742 spec->automute = 1;
17743 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang8c427222008-01-10 13:03:59 +010017744}
17745
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017746static void alc663_m51va_setup(struct hda_codec *codec)
17747{
17748 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017749 spec->autocfg.hp_pins[0] = 0x21;
17750 spec->autocfg.speaker_pins[0] = 0x14;
17751 spec->automute_mixer_nid[0] = 0x0c;
17752 spec->automute = 1;
17753 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017754 spec->ext_mic.pin = 0x18;
17755 spec->ext_mic.mux_idx = 0;
17756 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017757 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017758 spec->auto_mic = 1;
17759}
17760
Kailang Yangf1d4e282008-08-26 14:03:29 +020017761/* ***************** Mode1 ******************************/
Kailang Yangebb83ee2009-12-17 12:23:00 +010017762static void alc663_mode1_setup(struct hda_codec *codec)
17763{
17764 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017765 spec->autocfg.hp_pins[0] = 0x21;
17766 spec->autocfg.speaker_pins[0] = 0x14;
17767 spec->automute_mixer_nid[0] = 0x0c;
17768 spec->automute = 1;
17769 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017770 spec->ext_mic.pin = 0x18;
17771 spec->ext_mic.mux_idx = 0;
17772 spec->int_mic.pin = 0x19;
17773 spec->int_mic.mux_idx = 1;
17774 spec->auto_mic = 1;
17775}
17776
Kailang Yangf1d4e282008-08-26 14:03:29 +020017777/* ***************** Mode2 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017778static void alc662_mode2_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017779{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017780 struct alc_spec *spec = codec->spec;
17781 spec->autocfg.hp_pins[0] = 0x1b;
17782 spec->autocfg.speaker_pins[0] = 0x14;
17783 spec->automute = 1;
17784 spec->automute_mode = ALC_AUTOMUTE_PIN;
17785 spec->ext_mic.pin = 0x18;
17786 spec->ext_mic.mux_idx = 0;
17787 spec->int_mic.pin = 0x19;
17788 spec->int_mic.mux_idx = 1;
17789 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017790}
17791
Kailang Yangf1d4e282008-08-26 14:03:29 +020017792/* ***************** Mode3 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017793static void alc663_mode3_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017794{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017795 struct alc_spec *spec = codec->spec;
17796 spec->autocfg.hp_pins[0] = 0x21;
17797 spec->autocfg.hp_pins[0] = 0x15;
17798 spec->autocfg.speaker_pins[0] = 0x14;
17799 spec->automute = 1;
17800 spec->automute_mode = ALC_AUTOMUTE_PIN;
17801 spec->ext_mic.pin = 0x18;
17802 spec->ext_mic.mux_idx = 0;
17803 spec->int_mic.pin = 0x19;
17804 spec->int_mic.mux_idx = 1;
17805 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017806}
17807
Kailang Yangf1d4e282008-08-26 14:03:29 +020017808/* ***************** Mode4 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017809static void alc663_mode4_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017810{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017811 struct alc_spec *spec = codec->spec;
17812 spec->autocfg.hp_pins[0] = 0x21;
17813 spec->autocfg.speaker_pins[0] = 0x14;
17814 spec->autocfg.speaker_pins[1] = 0x16;
17815 spec->automute_mixer_nid[0] = 0x0c;
17816 spec->automute_mixer_nid[1] = 0x0e;
17817 spec->automute = 1;
17818 spec->automute_mode = ALC_AUTOMUTE_MIXER;
17819 spec->ext_mic.pin = 0x18;
17820 spec->ext_mic.mux_idx = 0;
17821 spec->int_mic.pin = 0x19;
17822 spec->int_mic.mux_idx = 1;
17823 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017824}
17825
Kailang Yangf1d4e282008-08-26 14:03:29 +020017826/* ***************** Mode5 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017827static void alc663_mode5_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017828{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017829 struct alc_spec *spec = codec->spec;
17830 spec->autocfg.hp_pins[0] = 0x15;
17831 spec->autocfg.speaker_pins[0] = 0x14;
17832 spec->autocfg.speaker_pins[1] = 0x16;
17833 spec->automute_mixer_nid[0] = 0x0c;
17834 spec->automute_mixer_nid[1] = 0x0e;
17835 spec->automute = 1;
17836 spec->automute_mode = ALC_AUTOMUTE_MIXER;
17837 spec->ext_mic.pin = 0x18;
17838 spec->ext_mic.mux_idx = 0;
17839 spec->int_mic.pin = 0x19;
17840 spec->int_mic.mux_idx = 1;
17841 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017842}
17843
Kailang Yangf1d4e282008-08-26 14:03:29 +020017844/* ***************** Mode6 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017845static void alc663_mode6_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017846{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017847 struct alc_spec *spec = codec->spec;
17848 spec->autocfg.hp_pins[0] = 0x1b;
17849 spec->autocfg.hp_pins[0] = 0x15;
17850 spec->autocfg.speaker_pins[0] = 0x14;
17851 spec->automute_mixer_nid[0] = 0x0c;
17852 spec->automute = 1;
17853 spec->automute_mode = ALC_AUTOMUTE_MIXER;
17854 spec->ext_mic.pin = 0x18;
17855 spec->ext_mic.mux_idx = 0;
17856 spec->int_mic.pin = 0x19;
17857 spec->int_mic.mux_idx = 1;
17858 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017859}
17860
Kailang Yangebb83ee2009-12-17 12:23:00 +010017861/* ***************** Mode7 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017862static void alc663_mode7_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010017863{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017864 struct alc_spec *spec = codec->spec;
17865 spec->autocfg.hp_pins[0] = 0x1b;
17866 spec->autocfg.hp_pins[0] = 0x21;
17867 spec->autocfg.speaker_pins[0] = 0x14;
17868 spec->autocfg.speaker_pins[0] = 0x17;
17869 spec->automute = 1;
17870 spec->automute_mode = ALC_AUTOMUTE_PIN;
17871 spec->ext_mic.pin = 0x18;
17872 spec->ext_mic.mux_idx = 0;
17873 spec->int_mic.pin = 0x19;
17874 spec->int_mic.mux_idx = 1;
17875 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017876}
17877
17878/* ***************** Mode8 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017879static void alc663_mode8_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010017880{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017881 struct alc_spec *spec = codec->spec;
17882 spec->autocfg.hp_pins[0] = 0x21;
17883 spec->autocfg.hp_pins[1] = 0x15;
17884 spec->autocfg.speaker_pins[0] = 0x14;
17885 spec->autocfg.speaker_pins[0] = 0x17;
17886 spec->automute = 1;
17887 spec->automute_mode = ALC_AUTOMUTE_PIN;
17888 spec->ext_mic.pin = 0x18;
17889 spec->ext_mic.mux_idx = 0;
17890 spec->int_mic.pin = 0x12;
17891 spec->int_mic.mux_idx = 9;
17892 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017893}
17894
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017895static void alc663_g71v_setup(struct hda_codec *codec)
Kailang Yang6dda9f42008-05-27 12:05:31 +020017896{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017897 struct alc_spec *spec = codec->spec;
17898 spec->autocfg.hp_pins[0] = 0x21;
17899 spec->autocfg.line_out_pins[0] = 0x15;
17900 spec->autocfg.speaker_pins[0] = 0x14;
17901 spec->automute = 1;
17902 spec->automute_mode = ALC_AUTOMUTE_AMP;
17903 spec->detect_line = 1;
17904 spec->automute_lines = 1;
17905 spec->ext_mic.pin = 0x18;
17906 spec->ext_mic.mux_idx = 0;
17907 spec->int_mic.pin = 0x12;
17908 spec->int_mic.mux_idx = 9;
17909 spec->auto_mic = 1;
Kailang Yang6dda9f42008-05-27 12:05:31 +020017910}
17911
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017912#define alc663_g50v_setup alc663_m51va_setup
17913
Takashi Iwaia9111322011-05-02 11:30:18 +020017914static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017915 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020017916 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017917
David Henningsson5f99f862011-01-04 15:24:24 +010017918 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017919 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
17920 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017921
David Henningsson5f99f862011-01-04 15:24:24 +010017922 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017923 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17924 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017925 { } /* end */
17926};
17927
Takashi Iwaia9111322011-05-02 11:30:18 +020017928static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020017929 /* Master Playback automatically created from Speaker and Headphone */
17930 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17931 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17932 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17933 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17934
David Henningsson8607f7c2010-12-20 14:43:54 +010017935 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17936 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010017937 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017938
David Henningsson28c4edb2010-12-20 14:24:29 +010017939 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17940 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010017941 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017942 { } /* end */
17943};
17944
Takashi Iwaicb53c622007-08-10 17:21:45 +020017945#ifdef CONFIG_SND_HDA_POWER_SAVE
17946#define alc662_loopbacks alc880_loopbacks
17947#endif
17948
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017949
Sasha Alexandrdef319f2009-06-16 16:00:15 -040017950/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017951#define alc662_pcm_analog_playback alc880_pcm_analog_playback
17952#define alc662_pcm_analog_capture alc880_pcm_analog_capture
17953#define alc662_pcm_digital_playback alc880_pcm_digital_playback
17954#define alc662_pcm_digital_capture alc880_pcm_digital_capture
17955
17956/*
17957 * configuration and preset
17958 */
Takashi Iwaiea734962011-01-17 11:29:34 +010017959static const char * const alc662_models[ALC662_MODEL_LAST] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017960 [ALC662_3ST_2ch_DIG] = "3stack-dig",
17961 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
17962 [ALC662_3ST_6ch] = "3stack-6ch",
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080017963 [ALC662_5ST_DIG] = "5stack-dig",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017964 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020017965 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010017966 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017967 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020017968 [ALC663_ASUS_M51VA] = "m51va",
17969 [ALC663_ASUS_G71V] = "g71v",
17970 [ALC663_ASUS_H13] = "h13",
17971 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017972 [ALC663_ASUS_MODE1] = "asus-mode1",
17973 [ALC662_ASUS_MODE2] = "asus-mode2",
17974 [ALC663_ASUS_MODE3] = "asus-mode3",
17975 [ALC663_ASUS_MODE4] = "asus-mode4",
17976 [ALC663_ASUS_MODE5] = "asus-mode5",
17977 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010017978 [ALC663_ASUS_MODE7] = "asus-mode7",
17979 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020017980 [ALC272_DELL] = "dell",
17981 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020017982 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017983 [ALC662_AUTO] = "auto",
17984};
17985
Takashi Iwaia9111322011-05-02 11:30:18 +020017986static const struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010017987 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020017988 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
17989 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017990 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
17991 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010017992 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017993 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
17994 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
17995 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
17996 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017997 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
17998 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017999 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018000 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18001 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18002 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18003 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18004 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018005 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018006 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18007 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018008 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18009 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18010 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18011 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018012 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018013 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18014 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18015 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018016 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18017 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18018 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18019 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018020 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018021 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18022 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018023 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018024 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18025 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18026 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018027 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018028 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018029 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18030 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018031 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18032 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18033 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018034 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018035 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18036 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018037 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018038 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018039 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018040 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18041 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18042 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018043 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018044 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18045 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018046 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018047 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018048 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018049 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018050 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18051 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018052 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018053 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Takashi Iwaiebb47242011-05-02 10:37:29 +020018054 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18055 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018056 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018057 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018058 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018059 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018060 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018061 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018062 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18063 ALC663_ASUS_H13),
Anisse Astier965b76d2011-02-10 13:14:44 +010018064 SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018065 {}
18066};
18067
Takashi Iwaia9111322011-05-02 11:30:18 +020018068static const struct alc_config_preset alc662_presets[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018069 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018070 .mixers = { alc662_3ST_2ch_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018071 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018072 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18073 .dac_nids = alc662_dac_nids,
18074 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018075 .dig_in_nid = ALC662_DIGIN_NID,
18076 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18077 .channel_mode = alc662_3ST_2ch_modes,
18078 .input_mux = &alc662_capture_source,
18079 },
18080 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018081 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018082 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018083 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18084 .dac_nids = alc662_dac_nids,
18085 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018086 .dig_in_nid = ALC662_DIGIN_NID,
18087 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18088 .channel_mode = alc662_3ST_6ch_modes,
18089 .need_dac_fix = 1,
18090 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018091 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018092 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018093 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018094 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018095 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18096 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018097 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18098 .channel_mode = alc662_3ST_6ch_modes,
18099 .need_dac_fix = 1,
18100 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018101 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018102 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018103 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018104 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018105 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18106 .dac_nids = alc662_dac_nids,
18107 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018108 .dig_in_nid = ALC662_DIGIN_NID,
18109 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18110 .channel_mode = alc662_5stack_modes,
18111 .input_mux = &alc662_capture_source,
18112 },
18113 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018114 .mixers = { alc662_lenovo_101e_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018115 .init_verbs = { alc662_init_verbs,
18116 alc662_eapd_init_verbs,
18117 alc662_sue_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018118 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18119 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018120 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18121 .channel_mode = alc662_3ST_2ch_modes,
18122 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018123 .unsol_event = alc_sku_unsol_event,
18124 .setup = alc662_lenovo_101e_setup,
18125 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018126 },
Kailang Yang291702f2007-10-16 14:28:03 +020018127 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018128 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018129 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018130 alc662_eapd_init_verbs,
Kailang Yang291702f2007-10-16 14:28:03 +020018131 alc662_eeepc_sue_init_verbs },
18132 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18133 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018134 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18135 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020018136 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018137 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018138 .init_hook = alc_inithook,
Kailang Yang291702f2007-10-16 14:28:03 +020018139 },
Kailang Yang8c427222008-01-10 13:03:59 +010018140 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018141 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018142 alc662_chmode_mixer },
18143 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018144 alc662_eapd_init_verbs,
Kailang Yang8c427222008-01-10 13:03:59 +010018145 alc662_eeepc_ep20_sue_init_verbs },
18146 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18147 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018148 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18149 .channel_mode = alc662_3ST_6ch_modes,
18150 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020018151 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018152 .setup = alc662_eeepc_ep20_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018153 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010018154 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018155 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018156 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018157 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018158 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018159 alc662_ecs_init_verbs },
18160 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18161 .dac_nids = alc662_dac_nids,
18162 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18163 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020018164 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018165 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018166 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018167 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018168 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018169 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018170 .init_verbs = { alc662_init_verbs,
18171 alc662_eapd_init_verbs,
18172 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018173 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18174 .dac_nids = alc662_dac_nids,
18175 .dig_out_nid = ALC662_DIGOUT_NID,
18176 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18177 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018178 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018179 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018180 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018181 },
18182 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018183 .mixers = { alc663_g71v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018184 .init_verbs = { alc662_init_verbs,
18185 alc662_eapd_init_verbs,
18186 alc663_g71v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018187 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18188 .dac_nids = alc662_dac_nids,
18189 .dig_out_nid = ALC662_DIGOUT_NID,
18190 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18191 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018192 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018193 .setup = alc663_g71v_setup,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018194 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018195 },
18196 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018197 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018198 .init_verbs = { alc662_init_verbs,
18199 alc662_eapd_init_verbs,
18200 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018201 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18202 .dac_nids = alc662_dac_nids,
18203 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18204 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018205 .setup = alc663_m51va_setup,
18206 .unsol_event = alc_sku_unsol_event,
18207 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018208 },
18209 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018210 .mixers = { alc663_g50v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018211 .init_verbs = { alc662_init_verbs,
18212 alc662_eapd_init_verbs,
18213 alc663_g50v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018214 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18215 .dac_nids = alc662_dac_nids,
18216 .dig_out_nid = ALC662_DIGOUT_NID,
18217 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18218 .channel_mode = alc662_3ST_6ch_modes,
18219 .input_mux = &alc663_capture_source,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018220 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018221 .setup = alc663_g50v_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018222 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018223 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018224 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018225 .mixers = { alc663_m51va_mixer },
18226 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018227 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018228 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018229 alc663_21jd_amic_init_verbs },
18230 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18231 .hp_nid = 0x03,
18232 .dac_nids = alc662_dac_nids,
18233 .dig_out_nid = ALC662_DIGOUT_NID,
18234 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18235 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018236 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018237 .setup = alc663_mode1_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018238 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018239 },
18240 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018241 .mixers = { alc662_1bjd_mixer },
18242 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018243 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018244 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018245 alc662_1bjd_amic_init_verbs },
18246 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18247 .dac_nids = alc662_dac_nids,
18248 .dig_out_nid = ALC662_DIGOUT_NID,
18249 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18250 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018251 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018252 .setup = alc662_mode2_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018253 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018254 },
18255 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018256 .mixers = { alc663_two_hp_m1_mixer },
18257 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018258 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018259 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018260 alc663_two_hp_amic_m1_init_verbs },
18261 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18262 .hp_nid = 0x03,
18263 .dac_nids = alc662_dac_nids,
18264 .dig_out_nid = ALC662_DIGOUT_NID,
18265 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18266 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018267 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018268 .setup = alc663_mode3_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018269 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018270 },
18271 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018272 .mixers = { alc663_asus_21jd_clfe_mixer },
18273 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018274 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018275 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018276 alc663_21jd_amic_init_verbs},
18277 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18278 .hp_nid = 0x03,
18279 .dac_nids = alc662_dac_nids,
18280 .dig_out_nid = ALC662_DIGOUT_NID,
18281 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18282 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018283 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018284 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018285 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018286 },
18287 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018288 .mixers = { alc663_asus_15jd_clfe_mixer },
18289 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018290 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018291 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018292 alc663_15jd_amic_init_verbs },
18293 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18294 .hp_nid = 0x03,
18295 .dac_nids = alc662_dac_nids,
18296 .dig_out_nid = ALC662_DIGOUT_NID,
18297 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18298 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018299 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018300 .setup = alc663_mode5_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018301 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018302 },
18303 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018304 .mixers = { alc663_two_hp_m2_mixer },
18305 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018306 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018307 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018308 alc663_two_hp_amic_m2_init_verbs },
18309 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18310 .hp_nid = 0x03,
18311 .dac_nids = alc662_dac_nids,
18312 .dig_out_nid = ALC662_DIGOUT_NID,
18313 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18314 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018315 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018316 .setup = alc663_mode6_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018317 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018318 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018319 [ALC663_ASUS_MODE7] = {
18320 .mixers = { alc663_mode7_mixer },
18321 .cap_mixer = alc662_auto_capture_mixer,
18322 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018323 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018324 alc663_mode7_init_verbs },
18325 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18326 .hp_nid = 0x03,
18327 .dac_nids = alc662_dac_nids,
18328 .dig_out_nid = ALC662_DIGOUT_NID,
18329 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18330 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018331 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018332 .setup = alc663_mode7_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018333 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018334 },
18335 [ALC663_ASUS_MODE8] = {
18336 .mixers = { alc663_mode8_mixer },
18337 .cap_mixer = alc662_auto_capture_mixer,
18338 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018339 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018340 alc663_mode8_init_verbs },
18341 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18342 .hp_nid = 0x03,
18343 .dac_nids = alc662_dac_nids,
18344 .dig_out_nid = ALC662_DIGOUT_NID,
18345 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18346 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018347 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018348 .setup = alc663_mode8_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018349 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018350 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018351 [ALC272_DELL] = {
18352 .mixers = { alc663_m51va_mixer },
18353 .cap_mixer = alc272_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018354 .init_verbs = { alc662_init_verbs,
18355 alc662_eapd_init_verbs,
18356 alc272_dell_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018357 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018358 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018359 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18360 .adc_nids = alc272_adc_nids,
18361 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18362 .capsrc_nids = alc272_capsrc_nids,
18363 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018364 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018365 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018366 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018367 },
18368 [ALC272_DELL_ZM1] = {
18369 .mixers = { alc663_m51va_mixer },
18370 .cap_mixer = alc662_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018371 .init_verbs = { alc662_init_verbs,
18372 alc662_eapd_init_verbs,
18373 alc272_dell_zm1_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018374 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018375 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018376 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18377 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018378 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018379 .capsrc_nids = alc662_capsrc_nids,
18380 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018381 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018382 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018383 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018384 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018385 [ALC272_SAMSUNG_NC10] = {
18386 .mixers = { alc272_nc10_mixer },
18387 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018388 alc662_eapd_init_verbs,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018389 alc663_21jd_amic_init_verbs },
18390 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18391 .dac_nids = alc272_dac_nids,
18392 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18393 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018394 /*.input_mux = &alc272_nc10_capture_source,*/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018395 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018396 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018397 .init_hook = alc_inithook,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018398 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018399};
18400
18401
18402/*
18403 * BIOS auto configuration
18404 */
18405
Takashi Iwai7085ec12009-10-02 09:03:58 +020018406/* convert from MIX nid to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018407static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018408{
Takashi Iwai604401a2011-04-27 15:14:23 +020018409 hda_nid_t list[5];
Takashi Iwai1304ac82011-04-06 15:16:21 +020018410 int i, num;
18411
18412 num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
18413 for (i = 0; i < num; i++) {
18414 if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
18415 return list[i];
18416 }
18417 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018418}
18419
Takashi Iwai604401a2011-04-27 15:14:23 +020018420/* go down to the selector widget before the mixer */
18421static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
18422{
18423 hda_nid_t srcs[5];
18424 int num = snd_hda_get_connections(codec, pin, srcs,
18425 ARRAY_SIZE(srcs));
18426 if (num != 1 ||
18427 get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
18428 return pin;
18429 return srcs[0];
18430}
18431
Takashi Iwai7085ec12009-10-02 09:03:58 +020018432/* get MIX nid connected to the given pin targeted to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018433static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018434 hda_nid_t dac)
18435{
David Henningssoncc1c4522010-11-24 14:17:47 +010018436 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018437 int i, num;
18438
Takashi Iwai604401a2011-04-27 15:14:23 +020018439 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018440 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18441 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018442 if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018443 return mix[i];
18444 }
18445 return 0;
18446}
18447
Takashi Iwaice764ab2011-04-27 16:35:23 +020018448/* select the connection from pin to DAC if needed */
18449static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
18450 hda_nid_t dac)
18451{
18452 hda_nid_t mix[5];
18453 int i, num;
18454
18455 pin = alc_go_down_to_selector(codec, pin);
18456 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18457 if (num < 2)
18458 return 0;
18459 for (i = 0; i < num; i++) {
18460 if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
18461 snd_hda_codec_update_cache(codec, pin, 0,
18462 AC_VERB_SET_CONNECT_SEL, i);
18463 return 0;
18464 }
18465 }
18466 return 0;
18467}
18468
Takashi Iwai7085ec12009-10-02 09:03:58 +020018469/* look for an empty DAC slot */
Takashi Iwai604401a2011-04-27 15:14:23 +020018470static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018471{
18472 struct alc_spec *spec = codec->spec;
18473 hda_nid_t srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018474 int i, num;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018475
Takashi Iwai604401a2011-04-27 15:14:23 +020018476 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018477 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018478 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018479 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018480 if (!nid)
18481 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018482 if (found_in_nid_list(nid, spec->multiout.dac_nids,
18483 spec->multiout.num_dacs))
18484 continue;
18485 if (spec->multiout.hp_nid == nid)
18486 continue;
18487 if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
18488 ARRAY_SIZE(spec->multiout.extra_out_nid)))
18489 continue;
18490 return nid;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018491 }
18492 return 0;
18493}
18494
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018495static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
18496{
18497 hda_nid_t sel = alc_go_down_to_selector(codec, pin);
18498 if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
18499 return alc_auto_look_for_dac(codec, pin);
18500 return 0;
18501}
18502
Takashi Iwai7085ec12009-10-02 09:03:58 +020018503/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018504static int alc_auto_fill_dac_nids(struct hda_codec *codec)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018505{
18506 struct alc_spec *spec = codec->spec;
Takashi Iwaicb053a82011-06-27 11:32:07 +020018507 const struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai350434e2011-06-30 21:29:12 +020018508 bool redone = false;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018509 int i;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018510
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018511 again:
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018512 spec->multiout.num_dacs = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018513 spec->multiout.hp_nid = 0;
18514 spec->multiout.extra_out_nid[0] = 0;
18515 memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
18516 spec->multiout.dac_nids = spec->private_dac_nids;
18517
18518 /* fill hard-wired DACs first */
18519 if (!redone) {
18520 for (i = 0; i < cfg->line_outs; i++)
18521 spec->private_dac_nids[i] =
18522 get_dac_if_single(codec, cfg->line_out_pins[i]);
18523 if (cfg->hp_outs)
18524 spec->multiout.hp_nid =
18525 get_dac_if_single(codec, cfg->hp_pins[0]);
18526 if (cfg->speaker_outs)
18527 spec->multiout.extra_out_nid[0] =
18528 get_dac_if_single(codec, cfg->speaker_pins[0]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018529 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018530
18531 for (i = 0; i < cfg->line_outs; i++) {
18532 hda_nid_t pin = cfg->line_out_pins[i];
18533 if (spec->private_dac_nids[i])
18534 continue;
18535 spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
18536 if (!spec->private_dac_nids[i] && !redone) {
18537 /* if we can't find primary DACs, re-probe without
18538 * checking the hard-wired DACs
18539 */
18540 redone = true;
18541 goto again;
18542 }
18543 }
18544
18545 for (i = 0; i < cfg->line_outs; i++) {
18546 if (spec->private_dac_nids[i])
18547 spec->multiout.num_dacs++;
18548 else
18549 memmove(spec->private_dac_nids + i,
18550 spec->private_dac_nids + i + 1,
18551 sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
18552 }
18553
Takashi Iwaibb8bf4d2011-07-06 13:07:54 +020018554 if (cfg->hp_outs && !spec->multiout.hp_nid)
18555 spec->multiout.hp_nid =
18556 alc_auto_look_for_dac(codec, cfg->hp_pins[0]);
18557 if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0])
18558 spec->multiout.extra_out_nid[0] =
18559 alc_auto_look_for_dac(codec, cfg->speaker_pins[0]);
18560
Takashi Iwai7085ec12009-10-02 09:03:58 +020018561 return 0;
18562}
18563
Takashi Iwai343a04b2011-07-06 14:28:39 +020018564static int alc_auto_add_vol_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +020018565 const char *pfx, int cidx,
18566 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018567{
Takashi Iwai97aaab72011-07-06 14:02:55 +020018568 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
18569 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018570}
18571
Takashi Iwai343a04b2011-07-06 14:28:39 +020018572#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
18573 alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai97aaab72011-07-06 14:02:55 +020018574
18575/* create a mute-switch for the given mixer widget;
18576 * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
18577 */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018578static int alc_auto_add_sw_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +020018579 const char *pfx, int cidx,
18580 hda_nid_t nid, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018581{
Takashi Iwai97aaab72011-07-06 14:02:55 +020018582 int type;
18583 unsigned long val;
18584 if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
18585 type = ALC_CTL_WIDGET_MUTE;
18586 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
18587 } else {
18588 type = ALC_CTL_BIND_MUTE;
18589 val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
18590 }
18591 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018592}
18593
Takashi Iwai343a04b2011-07-06 14:28:39 +020018594#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid) \
18595 alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018596
18597/* add playback controls from the parsed DAC table */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018598static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018599 const struct auto_pin_cfg *cfg)
18600{
18601 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018602 hda_nid_t nid, mix, pin;
18603 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018604
Takashi Iwaice764ab2011-04-27 16:35:23 +020018605 noutputs = cfg->line_outs;
18606 if (spec->multi_ios > 0)
18607 noutputs += spec->multi_ios;
18608
18609 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020018610 const char *name;
18611 int index;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018612 nid = spec->multiout.dac_nids[i];
18613 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018614 continue;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018615 if (i >= cfg->line_outs)
18616 pin = spec->multi_io[i - 1].pin;
18617 else
18618 pin = cfg->line_out_pins[i];
18619 mix = alc_auto_dac_to_mix(codec, pin, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018620 if (!mix)
18621 continue;
Takashi Iwai6843ca12011-06-24 11:03:58 +020018622 name = alc_get_line_out_pfx(spec, i, true, &index);
18623 if (!name) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018624 /* Center/LFE */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018625 err = alc_auto_add_vol_ctl(codec, "Center", 0, nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018626 if (err < 0)
18627 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018628 err = alc_auto_add_vol_ctl(codec, "LFE", 0, nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018629 if (err < 0)
18630 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018631 err = alc_auto_add_sw_ctl(codec, "Center", 0, mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018632 if (err < 0)
18633 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018634 err = alc_auto_add_sw_ctl(codec, "LFE", 0, mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018635 if (err < 0)
18636 return err;
18637 } else {
Takashi Iwai343a04b2011-07-06 14:28:39 +020018638 err = alc_auto_add_stereo_vol(codec, name, index, nid);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018639 if (err < 0)
18640 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018641 err = alc_auto_add_stereo_sw(codec, name, index, mix);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018642 if (err < 0)
18643 return err;
18644 }
18645 }
18646 return 0;
18647}
18648
18649/* add playback controls for speaker and HP outputs */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018650static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018651 hda_nid_t dac, const char *pfx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018652{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018653 struct alc_spec *spec = codec->spec;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018654 hda_nid_t mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018655 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018656
18657 if (!pin)
18658 return 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018659 if (!dac) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018660 /* the corresponding DAC is already occupied */
18661 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18662 return 0; /* no way */
18663 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018664 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018665 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18666 }
18667
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018668 mix = alc_auto_dac_to_mix(codec, pin, dac);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018669 if (!mix)
18670 return 0;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018671 err = alc_auto_add_stereo_vol(codec, pfx, 0, dac);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018672 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018673 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018674 err = alc_auto_add_stereo_sw(codec, pfx, 0, mix);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018675 if (err < 0)
18676 return err;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018677 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018678}
18679
Takashi Iwai343a04b2011-07-06 14:28:39 +020018680static int alc_auto_create_hp_out(struct hda_codec *codec)
18681{
18682 struct alc_spec *spec = codec->spec;
18683 return alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
18684 spec->multiout.hp_nid,
18685 "Headphone");
18686}
18687
18688static int alc_auto_create_speaker_out(struct hda_codec *codec)
18689{
18690 struct alc_spec *spec = codec->spec;
18691 return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0],
18692 spec->multiout.extra_out_nid[0],
18693 "Speaker");
18694}
18695
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018696/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020018697#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020018698 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018699
Takashi Iwai343a04b2011-07-06 14:28:39 +020018700static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018701 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018702 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018703{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018704 int i, num;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018705 hda_nid_t mix = 0;
Takashi Iwaice503f32010-07-30 10:37:29 +020018706 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018707
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018708 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaicd511552011-07-06 13:10:42 +020018709 nid = alc_go_down_to_selector(codec, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018710 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018711 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018712 if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018713 continue;
Takashi Iwaicd511552011-07-06 13:10:42 +020018714 mix = srcs[i];
18715 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018716 }
Takashi Iwaicd511552011-07-06 13:10:42 +020018717 if (!mix)
18718 return;
18719
18720 /* need the manual connection? */
18721 if (num > 1)
18722 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18723 /* unmute mixer widget inputs */
18724 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18725 AMP_IN_UNMUTE(0));
18726 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18727 AMP_IN_UNMUTE(1));
18728 /* initialize volume */
18729 if (query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
18730 nid = dac;
18731 else if (query_amp_caps(codec, mix, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
18732 nid = mix;
18733 else
18734 return;
18735 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18736 AMP_OUT_ZERO);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018737}
18738
Takashi Iwai343a04b2011-07-06 14:28:39 +020018739static void alc_auto_init_multi_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018740{
18741 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018742 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018743 int i;
18744
18745 for (i = 0; i <= HDA_SIDE; i++) {
18746 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18747 if (nid)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018748 alc_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018749 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018750 }
18751}
18752
Takashi Iwai343a04b2011-07-06 14:28:39 +020018753static void alc_auto_init_extra_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018754{
18755 struct alc_spec *spec = codec->spec;
18756 hda_nid_t pin;
18757
18758 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018759 if (pin)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018760 alc_auto_set_output_and_unmute(codec, pin, PIN_HP,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018761 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018762 pin = spec->autocfg.speaker_pins[0];
18763 if (pin)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018764 alc_auto_set_output_and_unmute(codec, pin, PIN_OUT,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018765 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018766}
18767
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020018768#define alc662_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020018769#define alc662_auto_init_input_src alc882_auto_init_input_src
18770
Takashi Iwaice764ab2011-04-27 16:35:23 +020018771/*
18772 * multi-io helper
18773 */
18774static int alc_auto_fill_multi_ios(struct hda_codec *codec,
18775 unsigned int location)
18776{
18777 struct alc_spec *spec = codec->spec;
18778 struct auto_pin_cfg *cfg = &spec->autocfg;
18779 int type, i, num_pins = 0;
18780
18781 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
18782 for (i = 0; i < cfg->num_inputs; i++) {
18783 hda_nid_t nid = cfg->inputs[i].pin;
18784 hda_nid_t dac;
18785 unsigned int defcfg, caps;
18786 if (cfg->inputs[i].type != type)
18787 continue;
18788 defcfg = snd_hda_codec_get_pincfg(codec, nid);
18789 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
18790 continue;
18791 if (location && get_defcfg_location(defcfg) != location)
18792 continue;
18793 caps = snd_hda_query_pin_caps(codec, nid);
18794 if (!(caps & AC_PINCAP_OUT))
18795 continue;
18796 dac = alc_auto_look_for_dac(codec, nid);
18797 if (!dac)
18798 continue;
18799 spec->multi_io[num_pins].pin = nid;
18800 spec->multi_io[num_pins].dac = dac;
18801 num_pins++;
Takashi Iwaidda14412011-05-02 11:29:30 +020018802 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018803 }
18804 }
18805 spec->multiout.num_dacs = 1;
18806 if (num_pins < 2)
18807 return 0;
18808 return num_pins;
18809}
18810
18811static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
18812 struct snd_ctl_elem_info *uinfo)
18813{
18814 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18815 struct alc_spec *spec = codec->spec;
18816
18817 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
18818 uinfo->count = 1;
18819 uinfo->value.enumerated.items = spec->multi_ios + 1;
18820 if (uinfo->value.enumerated.item > spec->multi_ios)
18821 uinfo->value.enumerated.item = spec->multi_ios;
18822 sprintf(uinfo->value.enumerated.name, "%dch",
18823 (uinfo->value.enumerated.item + 1) * 2);
18824 return 0;
18825}
18826
18827static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
18828 struct snd_ctl_elem_value *ucontrol)
18829{
18830 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18831 struct alc_spec *spec = codec->spec;
18832 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
18833 return 0;
18834}
18835
18836static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
18837{
18838 struct alc_spec *spec = codec->spec;
18839 hda_nid_t nid = spec->multi_io[idx].pin;
18840
18841 if (!spec->multi_io[idx].ctl_in)
18842 spec->multi_io[idx].ctl_in =
18843 snd_hda_codec_read(codec, nid, 0,
18844 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
18845 if (output) {
18846 snd_hda_codec_update_cache(codec, nid, 0,
18847 AC_VERB_SET_PIN_WIDGET_CONTROL,
18848 PIN_OUT);
18849 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
18850 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
18851 HDA_AMP_MUTE, 0);
18852 alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
18853 } else {
18854 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
18855 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
18856 HDA_AMP_MUTE, HDA_AMP_MUTE);
18857 snd_hda_codec_update_cache(codec, nid, 0,
18858 AC_VERB_SET_PIN_WIDGET_CONTROL,
18859 spec->multi_io[idx].ctl_in);
18860 }
18861 return 0;
18862}
18863
18864static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
18865 struct snd_ctl_elem_value *ucontrol)
18866{
18867 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18868 struct alc_spec *spec = codec->spec;
18869 int i, ch;
18870
18871 ch = ucontrol->value.enumerated.item[0];
18872 if (ch < 0 || ch > spec->multi_ios)
18873 return -EINVAL;
18874 if (ch == (spec->ext_channel_count - 1) / 2)
18875 return 0;
18876 spec->ext_channel_count = (ch + 1) * 2;
18877 for (i = 0; i < spec->multi_ios; i++)
18878 alc_set_multi_io(codec, i, i < ch);
18879 spec->multiout.max_channels = spec->ext_channel_count;
18880 return 1;
18881}
18882
Takashi Iwaia9111322011-05-02 11:30:18 +020018883static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +020018884 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
18885 .name = "Channel Mode",
18886 .info = alc_auto_ch_mode_info,
18887 .get = alc_auto_ch_mode_get,
18888 .put = alc_auto_ch_mode_put,
18889};
18890
Takashi Iwaicb053a82011-06-27 11:32:07 +020018891static int alc_auto_add_multi_channel_mode(struct hda_codec *codec,
18892 int (*fill_dac)(struct hda_codec *))
Takashi Iwaice764ab2011-04-27 16:35:23 +020018893{
18894 struct alc_spec *spec = codec->spec;
18895 struct auto_pin_cfg *cfg = &spec->autocfg;
18896 unsigned int location, defcfg;
18897 int num_pins;
18898
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018899 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) {
18900 /* use HP as primary out */
18901 cfg->speaker_outs = cfg->line_outs;
18902 memcpy(cfg->speaker_pins, cfg->line_out_pins,
18903 sizeof(cfg->speaker_pins));
18904 cfg->line_outs = cfg->hp_outs;
18905 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
18906 cfg->hp_outs = 0;
18907 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
18908 cfg->line_out_type = AUTO_PIN_HP_OUT;
Takashi Iwaicb053a82011-06-27 11:32:07 +020018909 if (fill_dac)
18910 fill_dac(codec);
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018911 }
Takashi Iwaice764ab2011-04-27 16:35:23 +020018912 if (cfg->line_outs != 1 ||
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018913 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
Takashi Iwaice764ab2011-04-27 16:35:23 +020018914 return 0;
18915
18916 defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
18917 location = get_defcfg_location(defcfg);
18918
18919 num_pins = alc_auto_fill_multi_ios(codec, location);
18920 if (num_pins > 0) {
18921 struct snd_kcontrol_new *knew;
18922
18923 knew = alc_kcontrol_new(spec);
18924 if (!knew)
18925 return -ENOMEM;
18926 *knew = alc_auto_channel_mode_enum;
18927 knew->name = kstrdup("Channel Mode", GFP_KERNEL);
18928 if (!knew->name)
18929 return -ENOMEM;
18930
18931 spec->multi_ios = num_pins;
18932 spec->ext_channel_count = 2;
18933 spec->multiout.num_dacs = num_pins + 1;
18934 }
18935 return 0;
18936}
18937
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018938static int alc662_parse_auto_config(struct hda_codec *codec)
18939{
18940 struct alc_spec *spec = codec->spec;
18941 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020018942 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018943
18944 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18945 alc662_ignore);
18946 if (err < 0)
18947 return err;
18948 if (!spec->autocfg.line_outs)
18949 return 0; /* can't find valid BIOS pin config */
18950
Takashi Iwai343a04b2011-07-06 14:28:39 +020018951 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018952 if (err < 0)
18953 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018954 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020018955 if (err < 0)
18956 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018957 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018958 if (err < 0)
18959 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018960 err = alc_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018961 spec->autocfg.speaker_pins[0],
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018962 spec->multiout.extra_out_nid[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018963 "Speaker");
18964 if (err < 0)
18965 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018966 err = alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018967 spec->multiout.hp_nid,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018968 "Headphone");
18969 if (err < 0)
18970 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020018971 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018972 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018973 return err;
18974
18975 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18976
Takashi Iwai757899a2010-07-30 10:48:14 +020018977 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018978
Takashi Iwai603c4012008-07-30 15:01:44 +020018979 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018980 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018981
18982 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020018983 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020018984
Takashi Iwaiee979a142008-09-02 15:42:20 +020018985 err = alc_auto_add_mic_boost(codec);
18986 if (err < 0)
18987 return err;
18988
Kailang Yang6227cdc2010-02-25 08:36:52 +010018989 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18990 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18991 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18992 else
18993 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018994
Takashi Iwai8c87286f2007-06-19 12:11:16 +020018995 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018996}
18997
18998/* additional initialization for auto-configuration model */
18999static void alc662_auto_init(struct hda_codec *codec)
19000{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019001 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020019002 alc_auto_init_multi_out(codec);
19003 alc_auto_init_extra_out(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019004 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019005 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019006 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019007 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019008 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019009}
19010
Todd Broch6be79482010-12-07 16:51:05 -080019011static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019012 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019013{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019014 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019015 return;
Todd Broch6be79482010-12-07 16:51:05 -080019016 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
19017 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
19018 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
19019 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
19020 (0 << AC_AMPCAP_MUTE_SHIFT)))
19021 printk(KERN_WARNING
19022 "hda_codec: failed to override amp caps for NID 0x2\n");
19023}
19024
David Henningsson6cb3b702010-09-09 08:51:44 +020019025enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040019026 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019027 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080019028 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019029 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +020019030 ALC662_FIXUP_SKU_IGNORE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019031};
19032
19033static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019034 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019035 .type = ALC_FIXUP_PINS,
19036 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -040019037 { 0x15, 0x99130112 }, /* subwoofer */
19038 { }
19039 }
19040 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019041 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019042 .type = ALC_FIXUP_PINS,
19043 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019044 { 0x17, 0x99130112 }, /* subwoofer */
19045 { }
19046 }
19047 },
Todd Broch6be79482010-12-07 16:51:05 -080019048 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019049 .type = ALC_FIXUP_FUNC,
19050 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019051 },
19052 [ALC662_FIXUP_CZC_P10T] = {
19053 .type = ALC_FIXUP_VERBS,
19054 .v.verbs = (const struct hda_verb[]) {
19055 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
19056 {}
19057 }
19058 },
David Henningsson94024cd2011-04-29 14:10:55 +020019059 [ALC662_FIXUP_SKU_IGNORE] = {
19060 .type = ALC_FIXUP_SKU,
19061 .v.sku = ALC_FIXUP_SKU_IGNORE,
Takashi Iwaic6b35872011-03-28 12:05:31 +020019062 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019063};
19064
Takashi Iwaia9111322011-05-02 11:30:18 +020019065static const struct snd_pci_quirk alc662_fixup_tbl[] = {
David Henningssona6c47a82011-02-10 15:39:19 +010019066 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +020019067 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Daniel T Chen2df03512010-10-10 22:39:28 -040019068 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050019069 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060019070 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020019071 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +010019072 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
David Henningsson6cb3b702010-09-09 08:51:44 +020019073 {}
19074};
19075
Todd Broch6be79482010-12-07 16:51:05 -080019076static const struct alc_model_fixup alc662_fixup_models[] = {
19077 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
19078 {}
19079};
David Henningsson6cb3b702010-09-09 08:51:44 +020019080
19081
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019082static int patch_alc662(struct hda_codec *codec)
19083{
19084 struct alc_spec *spec;
19085 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020019086 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019087
19088 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19089 if (!spec)
19090 return -ENOMEM;
19091
19092 codec->spec = spec;
19093
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020019094 spec->mixer_nid = 0x0b;
19095
Kailang Yangda00c242010-03-19 11:23:45 +010019096 alc_auto_parse_customize_define(codec);
19097
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019098 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19099
Kailang Yang693194f2010-10-21 08:51:48 +020019100 coef = alc_read_coef_idx(codec, 0);
19101 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019102 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020019103 else if (coef & (1 << 14) &&
19104 codec->bus->pci->subsystem_vendor == 0x1025 &&
19105 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019106 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020019107 else if (coef == 0x4011)
19108 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010019109
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019110 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19111 alc662_models,
19112 alc662_cfg_tbl);
19113 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019114 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19115 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019116 board_config = ALC662_AUTO;
19117 }
19118
19119 if (board_config == ALC662_AUTO) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019120 alc_pick_fixup(codec, alc662_fixup_models,
19121 alc662_fixup_tbl, alc662_fixups);
19122 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019123 /* automatic parse from the BIOS config */
19124 err = alc662_parse_auto_config(codec);
19125 if (err < 0) {
19126 alc_free(codec);
19127 return err;
Takashi Iwai8c87286f2007-06-19 12:11:16 +020019128 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019129 printk(KERN_INFO
19130 "hda_codec: Cannot set up configuration "
19131 "from BIOS. Using base mode...\n");
19132 board_config = ALC662_3ST_2ch_DIG;
19133 }
19134 }
19135
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019136 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019137 err = snd_hda_attach_beep_device(codec, 0x1);
19138 if (err < 0) {
19139 alc_free(codec);
19140 return err;
19141 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019142 }
19143
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019144 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019145 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019146
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019147 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19148 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19149
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019150 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19151 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19152
Takashi Iwaidd704692009-08-11 08:45:11 +020019153 if (!spec->adc_nids) {
19154 spec->adc_nids = alc662_adc_nids;
19155 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19156 }
19157 if (!spec->capsrc_nids)
19158 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019159
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019160 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019161 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019162
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019163 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019164 switch (codec->vendor_id) {
19165 case 0x10ec0662:
19166 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19167 break;
19168 case 0x10ec0272:
19169 case 0x10ec0663:
19170 case 0x10ec0665:
19171 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19172 break;
19173 case 0x10ec0273:
19174 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19175 break;
19176 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019177 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019178 spec->vmaster_nid = 0x02;
19179
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019180 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
19181
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019182 codec->patch_ops = alc_patch_ops;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019183 if (board_config == ALC662_AUTO)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019184 spec->init_hook = alc662_auto_init;
Takashi Iwai1c7161532011-04-07 10:37:16 +020019185 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +020019186
Kailang Yangbf1b0222010-10-21 08:49:56 +020019187 alc_init_jacks(codec);
19188
Takashi Iwaicb53c622007-08-10 17:21:45 +020019189#ifdef CONFIG_SND_HDA_POWER_SAVE
19190 if (!spec->loopback.amplist)
19191 spec->loopback.amplist = alc662_loopbacks;
19192#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019193
19194 return 0;
19195}
19196
Kailang Yang274693f2009-12-03 10:07:50 +010019197static int patch_alc888(struct hda_codec *codec)
19198{
19199 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19200 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010019201 if (codec->vendor_id == 0x10ec0887)
19202 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
19203 else
19204 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019205 if (!codec->chip_name) {
19206 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019207 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019208 }
19209 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019210 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019211 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019212}
19213
Kailang Yangb478b992011-05-18 11:51:15 +020019214static int patch_alc899(struct hda_codec *codec)
19215{
19216 if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
19217 kfree(codec->chip_name);
19218 codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
19219 }
19220 return patch_alc882(codec);
19221}
19222
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019223/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019224 * ALC680 support
19225 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019226#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019227#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19228#define alc680_modes alc260_modes
19229
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019230static const hda_nid_t alc680_dac_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019231 /* Lout1, Lout2, hp */
19232 0x02, 0x03, 0x04
19233};
19234
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019235static const hda_nid_t alc680_adc_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019236 /* ADC0-2 */
19237 /* DMIC, MIC, Line-in*/
19238 0x07, 0x08, 0x09
19239};
19240
Kailang Yangc69aefa2010-08-17 10:39:22 +020019241/*
19242 * Analog capture ADC cgange
19243 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019244static void alc680_rec_autoswitch(struct hda_codec *codec)
19245{
19246 struct alc_spec *spec = codec->spec;
19247 struct auto_pin_cfg *cfg = &spec->autocfg;
19248 int pin_found = 0;
19249 int type_found = AUTO_PIN_LAST;
19250 hda_nid_t nid;
19251 int i;
19252
19253 for (i = 0; i < cfg->num_inputs; i++) {
19254 nid = cfg->inputs[i].pin;
Takashi Iwai06dec222011-05-17 10:00:16 +020019255 if (!is_jack_detectable(codec, nid))
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019256 continue;
19257 if (snd_hda_jack_detect(codec, nid)) {
19258 if (cfg->inputs[i].type < type_found) {
19259 type_found = cfg->inputs[i].type;
19260 pin_found = nid;
19261 }
19262 }
19263 }
19264
19265 nid = 0x07;
19266 if (pin_found)
19267 snd_hda_get_connections(codec, pin_found, &nid, 1);
19268
19269 if (nid != spec->cur_adc)
19270 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19271 spec->cur_adc = nid;
19272 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19273 spec->cur_adc_format);
19274}
19275
Kailang Yangc69aefa2010-08-17 10:39:22 +020019276static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19277 struct hda_codec *codec,
19278 unsigned int stream_tag,
19279 unsigned int format,
19280 struct snd_pcm_substream *substream)
19281{
19282 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019283
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019284 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019285 spec->cur_adc_stream_tag = stream_tag;
19286 spec->cur_adc_format = format;
19287
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019288 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019289 return 0;
19290}
19291
19292static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19293 struct hda_codec *codec,
19294 struct snd_pcm_substream *substream)
19295{
19296 snd_hda_codec_cleanup_stream(codec, 0x07);
19297 snd_hda_codec_cleanup_stream(codec, 0x08);
19298 snd_hda_codec_cleanup_stream(codec, 0x09);
19299 return 0;
19300}
19301
Takashi Iwaia9111322011-05-02 11:30:18 +020019302static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019303 .substreams = 1, /* can be overridden */
19304 .channels_min = 2,
19305 .channels_max = 2,
19306 /* NID is set in alc_build_pcms */
19307 .ops = {
19308 .prepare = alc680_capture_pcm_prepare,
19309 .cleanup = alc680_capture_pcm_cleanup
19310 },
19311};
19312
Takashi Iwaia9111322011-05-02 11:30:18 +020019313static const struct snd_kcontrol_new alc680_base_mixer[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019314 /* output mixer control */
19315 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19316 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19317 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19318 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019319 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19320 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19321 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019322 { }
19323};
19324
Takashi Iwaia9111322011-05-02 11:30:18 +020019325static const struct hda_bind_ctls alc680_bind_cap_vol = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019326 .ops = &snd_hda_bind_vol,
19327 .values = {
19328 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19329 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19330 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19331 0
19332 },
19333};
19334
Takashi Iwaia9111322011-05-02 11:30:18 +020019335static const struct hda_bind_ctls alc680_bind_cap_switch = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019336 .ops = &snd_hda_bind_sw,
19337 .values = {
19338 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19339 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19340 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19341 0
19342 },
19343};
19344
Takashi Iwaia9111322011-05-02 11:30:18 +020019345static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019346 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19347 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019348 { } /* end */
19349};
19350
19351/*
19352 * generic initialization of ADC, input mixers and output mixers
19353 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019354static const struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019355 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19356 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19357 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019358
Kailang Yangc69aefa2010-08-17 10:39:22 +020019359 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19360 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19361 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19362 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19363 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19364 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019365
19366 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19367 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19368 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19369 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19370 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019371
19372 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19373 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019374 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019375
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019376 { }
19377};
19378
Kailang Yangc69aefa2010-08-17 10:39:22 +020019379/* toggle speaker-output according to the hp-jack state */
19380static void alc680_base_setup(struct hda_codec *codec)
19381{
19382 struct alc_spec *spec = codec->spec;
19383
19384 spec->autocfg.hp_pins[0] = 0x16;
19385 spec->autocfg.speaker_pins[0] = 0x14;
19386 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019387 spec->autocfg.num_inputs = 2;
19388 spec->autocfg.inputs[0].pin = 0x18;
19389 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19390 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019391 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Takashi Iwaid922b512011-04-28 12:18:53 +020019392 spec->automute = 1;
19393 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019394}
19395
19396static void alc680_unsol_event(struct hda_codec *codec,
19397 unsigned int res)
19398{
19399 if ((res >> 26) == ALC880_HP_EVENT)
Takashi Iwaid922b512011-04-28 12:18:53 +020019400 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019401 if ((res >> 26) == ALC880_MIC_EVENT)
19402 alc680_rec_autoswitch(codec);
19403}
19404
19405static void alc680_inithook(struct hda_codec *codec)
19406{
Takashi Iwaid922b512011-04-28 12:18:53 +020019407 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019408 alc680_rec_autoswitch(codec);
19409}
19410
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019411/* create input playback/capture controls for the given pin */
19412static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19413 const char *ctlname, int idx)
19414{
19415 hda_nid_t dac;
19416 int err;
19417
19418 switch (nid) {
19419 case 0x14:
19420 dac = 0x02;
19421 break;
19422 case 0x15:
19423 dac = 0x03;
19424 break;
19425 case 0x16:
19426 dac = 0x04;
19427 break;
19428 default:
19429 return 0;
19430 }
19431 if (spec->multiout.dac_nids[0] != dac &&
19432 spec->multiout.dac_nids[1] != dac) {
19433 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19434 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19435 HDA_OUTPUT));
19436 if (err < 0)
19437 return err;
19438
19439 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19440 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19441
19442 if (err < 0)
19443 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020019444 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019445 }
19446
19447 return 0;
19448}
19449
19450/* add playback controls from the parsed DAC table */
19451static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19452 const struct auto_pin_cfg *cfg)
19453{
19454 hda_nid_t nid;
19455 int err;
19456
19457 spec->multiout.dac_nids = spec->private_dac_nids;
19458
19459 nid = cfg->line_out_pins[0];
19460 if (nid) {
19461 const char *name;
Takashi Iwai2e925dd2011-06-24 11:27:22 +020019462 int index;
19463 name = alc_get_line_out_pfx(spec, 0, true, &index);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019464 err = alc680_new_analog_output(spec, nid, name, 0);
19465 if (err < 0)
19466 return err;
19467 }
19468
19469 nid = cfg->speaker_pins[0];
19470 if (nid) {
19471 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19472 if (err < 0)
19473 return err;
19474 }
19475 nid = cfg->hp_pins[0];
19476 if (nid) {
19477 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19478 if (err < 0)
19479 return err;
19480 }
19481
19482 return 0;
19483}
19484
19485static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19486 hda_nid_t nid, int pin_type)
19487{
19488 alc_set_pin_output(codec, nid, pin_type);
19489}
19490
19491static void alc680_auto_init_multi_out(struct hda_codec *codec)
19492{
19493 struct alc_spec *spec = codec->spec;
19494 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19495 if (nid) {
19496 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19497 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19498 }
19499}
19500
19501static void alc680_auto_init_hp_out(struct hda_codec *codec)
19502{
19503 struct alc_spec *spec = codec->spec;
19504 hda_nid_t pin;
19505
19506 pin = spec->autocfg.hp_pins[0];
19507 if (pin)
19508 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19509 pin = spec->autocfg.speaker_pins[0];
19510 if (pin)
19511 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19512}
19513
19514/* pcm configuration: identical with ALC880 */
19515#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19516#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19517#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19518#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019519#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019520
19521/*
19522 * BIOS auto configuration
19523 */
19524static int alc680_parse_auto_config(struct hda_codec *codec)
19525{
19526 struct alc_spec *spec = codec->spec;
19527 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019528 static const hda_nid_t alc680_ignore[] = { 0 };
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019529
19530 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19531 alc680_ignore);
19532 if (err < 0)
19533 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019534
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019535 if (!spec->autocfg.line_outs) {
19536 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19537 spec->multiout.max_channels = 2;
19538 spec->no_analog = 1;
19539 goto dig_only;
19540 }
19541 return 0; /* can't find valid BIOS pin config */
19542 }
19543 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19544 if (err < 0)
19545 return err;
19546
19547 spec->multiout.max_channels = 2;
19548
19549 dig_only:
19550 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019551 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019552 if (spec->kctls.list)
19553 add_mixer(spec, spec->kctls.list);
19554
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019555 err = alc_auto_add_mic_boost(codec);
19556 if (err < 0)
19557 return err;
19558
19559 return 1;
19560}
19561
19562#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19563
19564/* init callback for auto-configuration model -- overriding the default init */
19565static void alc680_auto_init(struct hda_codec *codec)
19566{
19567 struct alc_spec *spec = codec->spec;
19568 alc680_auto_init_multi_out(codec);
19569 alc680_auto_init_hp_out(codec);
19570 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019571 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019572 if (spec->unsol_event)
19573 alc_inithook(codec);
19574}
19575
19576/*
19577 * configuration and preset
19578 */
Takashi Iwaiea734962011-01-17 11:29:34 +010019579static const char * const alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019580 [ALC680_BASE] = "base",
19581 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019582};
19583
Takashi Iwaia9111322011-05-02 11:30:18 +020019584static const struct snd_pci_quirk alc680_cfg_tbl[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019585 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19586 {}
19587};
19588
Takashi Iwaia9111322011-05-02 11:30:18 +020019589static const struct alc_config_preset alc680_presets[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019590 [ALC680_BASE] = {
19591 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020019592 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019593 .init_verbs = { alc680_init_verbs },
19594 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19595 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019596 .dig_out_nid = ALC680_DIGOUT_NID,
19597 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19598 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020019599 .unsol_event = alc680_unsol_event,
19600 .setup = alc680_base_setup,
19601 .init_hook = alc680_inithook,
19602
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019603 },
19604};
19605
19606static int patch_alc680(struct hda_codec *codec)
19607{
19608 struct alc_spec *spec;
19609 int board_config;
19610 int err;
19611
19612 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19613 if (spec == NULL)
19614 return -ENOMEM;
19615
19616 codec->spec = spec;
19617
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020019618 /* ALC680 has no aa-loopback mixer */
19619
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019620 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19621 alc680_models,
19622 alc680_cfg_tbl);
19623
19624 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19625 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19626 codec->chip_name);
19627 board_config = ALC680_AUTO;
19628 }
19629
19630 if (board_config == ALC680_AUTO) {
19631 /* automatic parse from the BIOS config */
19632 err = alc680_parse_auto_config(codec);
19633 if (err < 0) {
19634 alc_free(codec);
19635 return err;
19636 } else if (!err) {
19637 printk(KERN_INFO
19638 "hda_codec: Cannot set up configuration "
19639 "from BIOS. Using base mode...\n");
19640 board_config = ALC680_BASE;
19641 }
19642 }
19643
19644 if (board_config != ALC680_AUTO)
19645 setup_preset(codec, &alc680_presets[board_config]);
19646
19647 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019648 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019649 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019650 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019651
19652 if (!spec->adc_nids) {
19653 spec->adc_nids = alc680_adc_nids;
19654 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19655 }
19656
19657 if (!spec->cap_mixer)
19658 set_capture_mixer(codec);
19659
19660 spec->vmaster_nid = 0x02;
19661
19662 codec->patch_ops = alc_patch_ops;
19663 if (board_config == ALC680_AUTO)
19664 spec->init_hook = alc680_auto_init;
19665
19666 return 0;
19667}
19668
19669/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019670 * patch entries
19671 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019672static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +020019673 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019674 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019675 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019676 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019677 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019678 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019679 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019680 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019681 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +020019682 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019683 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019684 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019685 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19686 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19687 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019688 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019689 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019690 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19691 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019692 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019693 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019694 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019695 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019696 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019697 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019698 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019699 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019700 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019701 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019702 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019703 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010019704 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020019705 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai4953550a2009-06-30 15:28:30 +020019706 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019707 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai4953550a2009-06-30 15:28:30 +020019708 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019709 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Kailang Yangb478b992011-05-18 11:51:15 +020019710 { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019711 {} /* terminator */
19712};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019713
19714MODULE_ALIAS("snd-hda-codec-id:10ec*");
19715
19716MODULE_LICENSE("GPL");
19717MODULE_DESCRIPTION("Realtek HD-audio codec");
19718
19719static struct hda_codec_preset_list realtek_list = {
19720 .preset = snd_hda_preset_realtek,
19721 .owner = THIS_MODULE,
19722};
19723
19724static int __init patch_realtek_init(void)
19725{
19726 return snd_hda_add_codec_preset(&realtek_list);
19727}
19728
19729static void __exit patch_realtek_exit(void)
19730{
19731 snd_hda_delete_codec_preset(&realtek_list);
19732}
19733
19734module_init(patch_realtek_init)
19735module_exit(patch_realtek_exit)