blob: 524ff26417e3be4d8e1fcfb0220376ad8ac3de2e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Kailang Yangccc656c2006-10-17 12:32:26 +020036#define ALC880_FRONT_EVENT 0x01
37#define ALC880_DCVOL_EVENT 0x02
38#define ALC880_HP_EVENT 0x04
39#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ALC880 board config type */
42enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 ALC880_3ST,
44 ALC880_3ST_DIG,
45 ALC880_5ST,
46 ALC880_5ST_DIG,
47 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020048 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020049 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020050 ALC880_6ST_DIG,
51 ALC880_F1734,
52 ALC880_ASUS,
53 ALC880_ASUS_DIG,
54 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010055 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010056 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020057 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020058 ALC880_UNIWILL,
59 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010060 ALC880_CLEVO,
61 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010062 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010063 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020064 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020065#ifdef CONFIG_SND_DEBUG
66 ALC880_TEST,
67#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010068 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020069 ALC880_MODEL_LAST /* last tag */
70};
71
72/* ALC260 models */
73enum {
74 ALC260_BASIC,
75 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020076 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010077 ALC260_HP_3013,
78 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010079 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020080 ALC260_WILL,
81 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010082 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010083#ifdef CONFIG_SND_DEBUG
84 ALC260_TEST,
85#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010086 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020087 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
Kailang Yangdf694da2005-12-05 19:42:22 +010090/* ALC262 models */
91enum {
92 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020093 ALC262_HIPPO,
94 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010095 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020096 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010097 ALC262_HP_BPC_D7000_WL,
98 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010099 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +0100100 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200101 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200102 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200103 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200104 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100105 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200106 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200107 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200108 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000109 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100110 ALC262_AUTO,
111 ALC262_MODEL_LAST /* last tag */
112};
113
Kailang Yanga361d842007-06-05 12:30:55 +0200114/* ALC268 models */
115enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200116 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200118 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200119 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100120 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200121 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100122 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100123 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100124#ifdef CONFIG_SND_DEBUG
125 ALC268_TEST,
126#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200127 ALC268_AUTO,
128 ALC268_MODEL_LAST /* last tag */
129};
130
Kailang Yangf6a92242007-12-13 16:52:54 +0100131/* ALC269 models */
132enum {
133 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200134 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100135 ALC269_AMIC,
136 ALC269_DMIC,
137 ALC269VB_AMIC,
138 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100139 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000140 ALC269_LIFEBOOK,
Kailang Yangfe3eb0a2010-08-06 10:02:57 +0200141 ALC271_ACER,
Kailang Yangf6a92242007-12-13 16:52:54 +0100142 ALC269_AUTO,
143 ALC269_MODEL_LAST /* last tag */
144};
145
Kailang Yangdf694da2005-12-05 19:42:22 +0100146/* ALC861 models */
147enum {
148 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200149 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_3ST_DIG,
151 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200152 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200153 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200154 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100155 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100156 ALC861_AUTO,
157 ALC861_MODEL_LAST,
158};
159
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160/* ALC861-VD models */
161enum {
162 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200163 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100164 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_3ST,
166 ALC861VD_3ST_DIG,
167 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200168 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200169 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200170 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100171 ALC861VD_AUTO,
172 ALC861VD_MODEL_LAST,
173};
174
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200175/* ALC662 models */
176enum {
177 ALC662_3ST_2ch_DIG,
178 ALC662_3ST_6ch_DIG,
179 ALC662_3ST_6ch,
180 ALC662_5ST_DIG,
181 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200182 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100183 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200184 ALC663_ASUS_M51VA,
185 ALC663_ASUS_G71V,
186 ALC663_ASUS_H13,
187 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200188 ALC662_ECS,
189 ALC663_ASUS_MODE1,
190 ALC662_ASUS_MODE2,
191 ALC663_ASUS_MODE3,
192 ALC663_ASUS_MODE4,
193 ALC663_ASUS_MODE5,
194 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100195 ALC663_ASUS_MODE7,
196 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200197 ALC272_DELL,
198 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200199 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200200 ALC662_AUTO,
201 ALC662_MODEL_LAST,
202};
203
Kailang Yangdf694da2005-12-05 19:42:22 +0100204/* ALC882 models */
205enum {
206 ALC882_3ST_DIG,
207 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200208 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200209 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_TARGA,
211 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200212 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100213 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800214 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200215 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200216 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100217 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200218 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800219 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 ALC883_3ST_2ch_DIG,
221 ALC883_3ST_6ch_DIG,
222 ALC883_3ST_6ch,
223 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200224 ALC883_TARGA_DIG,
225 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200226 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200227 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200228 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800229 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100230 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200231 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200232 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200233 ALC883_MEDION,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +0200234 ALC883_MEDION_WIM2160,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100235 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200236 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200237 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200238 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200239 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200240 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200241 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100242 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100243 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430244 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100245 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100246 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800247 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200248 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200249 ALC889A_INTEL,
250 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200251 ALC888_ASUS_M90V,
252 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200253 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100254 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200255 ALC883_SONY_VAIO_TT,
Takashi Iwai49535502009-06-30 15:28:30 +0200256 ALC882_AUTO,
257 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200258};
259
Takashi Iwaid4a86d82010-06-23 17:51:26 +0200260/* ALC680 models */
261enum {
262 ALC680_BASE,
263 ALC680_AUTO,
264 ALC680_MODEL_LAST,
265};
266
Kailang Yangdf694da2005-12-05 19:42:22 +0100267/* for GPIO Poll */
268#define GPIO_MASK 0x03
269
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200270/* extra amp-initialization sequence types */
271enum {
272 ALC_INIT_NONE,
273 ALC_INIT_DEFAULT,
274 ALC_INIT_GPIO1,
275 ALC_INIT_GPIO2,
276 ALC_INIT_GPIO3,
277};
278
Takashi Iwai6c819492009-08-10 18:47:44 +0200279struct alc_mic_route {
280 hda_nid_t pin;
281 unsigned char mux_idx;
282 unsigned char amix_idx;
283};
284
285#define MUX_IDX_UNDEF ((unsigned char)-1)
286
Kailang Yangda00c242010-03-19 11:23:45 +0100287struct alc_customize_define {
288 unsigned int sku_cfg;
289 unsigned char port_connectivity;
290 unsigned char check_sum;
291 unsigned char customization;
292 unsigned char external_amp;
293 unsigned int enable_pcbeep:1;
294 unsigned int platform_type:1;
295 unsigned int swap:1;
296 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +0200297 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +0100298};
299
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100300struct alc_fixup;
301
Takashi Iwaice764ab2011-04-27 16:35:23 +0200302struct alc_multi_io {
303 hda_nid_t pin; /* multi-io widget pin NID */
304 hda_nid_t dac; /* DAC to be connected */
305 unsigned int ctl_in; /* cached input-pin control value */
306};
307
Takashi Iwaid922b512011-04-28 12:18:53 +0200308enum {
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200309 ALC_AUTOMUTE_PIN, /* change the pin control */
310 ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */
311 ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */
Takashi Iwaid922b512011-04-28 12:18:53 +0200312};
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314struct alc_spec {
315 /* codec parameterization */
Takashi Iwaia9111322011-05-02 11:30:18 +0200316 const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 unsigned int num_mixers;
Takashi Iwaia9111322011-05-02 11:30:18 +0200318 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100319 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200321 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200322 * don't forget NULL
323 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200324 */
325 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200327 char stream_name_analog[32]; /* analog PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200328 const struct hda_pcm_stream *stream_analog_playback;
329 const struct hda_pcm_stream *stream_analog_capture;
330 const struct hda_pcm_stream *stream_analog_alt_playback;
331 const struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200333 char stream_name_digital[32]; /* digital PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200334 const struct hda_pcm_stream *stream_digital_playback;
335 const struct hda_pcm_stream *stream_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200338 struct hda_multi_out multiout; /* playback set-up
339 * max_channels, dacs must be set
340 * dig_out_nid and hp_nid are optional
341 */
Takashi Iwai63300792008-01-24 15:31:36 +0100342 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100343 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100344 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 /* capture */
347 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200348 const hda_nid_t *adc_nids;
349 const hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200350 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Takashi Iwai840b64c2010-07-13 22:49:01 +0200352 /* capture setup for dynamic dual-adc switch */
353 unsigned int cur_adc_idx;
354 hda_nid_t cur_adc;
355 unsigned int cur_adc_stream_tag;
356 unsigned int cur_adc_format;
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200359 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 const struct hda_input_mux *input_mux;
361 unsigned int cur_mux[3];
Takashi Iwai6c819492009-08-10 18:47:44 +0200362 struct alc_mic_route ext_mic;
Takashi Iwai8ed99d92011-05-17 12:05:02 +0200363 struct alc_mic_route dock_mic;
Takashi Iwai6c819492009-08-10 18:47:44 +0200364 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100367 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200369 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200370 int const_channel_count;
371 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100374 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200375
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200376 /* dynamic controls, init_verbs and input_mux */
377 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100378 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200379 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200380 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200381 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200382 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
383 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100384
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100385 /* hooks */
386 void (*init_hook)(struct hda_codec *codec);
387 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100388#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500389 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100390#endif
Takashi Iwai1c716152011-04-07 10:37:16 +0200391 void (*shutup)(struct hda_codec *codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100392
Takashi Iwai834be882006-03-01 14:16:17 +0100393 /* for pin sensing */
Takashi Iwai834be882006-03-01 14:16:17 +0100394 unsigned int jack_present: 1;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200395 unsigned int line_jack_present:1;
Takashi Iwaie9427962011-04-28 15:46:07 +0200396 unsigned int master_mute:1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200397 unsigned int auto_mic:1;
Takashi Iwaid922b512011-04-28 12:18:53 +0200398 unsigned int automute:1; /* HP automute enabled */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200399 unsigned int detect_line:1; /* Line-out detection enabled */
400 unsigned int automute_lines:1; /* automute line-out as well */
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200401 unsigned int automute_hp_lo:1; /* both HP and LO available */
Takashi Iwaicb53c622007-08-10 17:21:45 +0200402
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100403 /* other flags */
404 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200405 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai584c0c42011-03-10 12:51:11 +0100406 unsigned int single_input_src:1;
Takashi Iwaid922b512011-04-28 12:18:53 +0200407
408 /* auto-mute control */
409 int automute_mode;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200410 hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
Takashi Iwaid922b512011-04-28 12:18:53 +0200411
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200412 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200413 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100414
Takashi Iwai2134ea42008-01-10 16:53:55 +0100415 /* for virtual master */
416 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200417#ifdef CONFIG_SND_HDA_POWER_SAVE
418 struct hda_loopback_check loopback;
419#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200420
421 /* for PLL fix */
422 hda_nid_t pll_nid;
423 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100424
425 /* fix-up list */
426 int fixup_id;
427 const struct alc_fixup *fixup_list;
428 const char *fixup_name;
Takashi Iwaice764ab2011-04-27 16:35:23 +0200429
430 /* multi-io */
431 int multi_ios;
432 struct alc_multi_io multi_io[4];
Kailang Yangdf694da2005-12-05 19:42:22 +0100433};
434
435/*
436 * configuration template - to be copied to the spec instance
437 */
438struct alc_config_preset {
Takashi Iwaia9111322011-05-02 11:30:18 +0200439 const struct snd_kcontrol_new *mixers[5]; /* should be identical size
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200440 * with spec
441 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200442 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100443 const struct hda_verb *init_verbs[5];
444 unsigned int num_dacs;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200445 const hda_nid_t *dac_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100446 hda_nid_t dig_out_nid; /* optional */
447 hda_nid_t hp_nid; /* optional */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200448 const hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100449 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200450 const hda_nid_t *adc_nids;
451 const hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100452 hda_nid_t dig_in_nid;
453 unsigned int num_channel_mode;
454 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200455 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200456 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200457 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100458 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100459 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200460 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100461 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200462#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +0200463 const struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500464 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200465#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466};
467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469/*
470 * input MUX handling
471 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200472static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
473 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
475 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
476 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200477 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
478 if (mux_idx >= spec->num_mux_defs)
479 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100480 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
481 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200482 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
484
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200485static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
486 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
489 struct alc_spec *spec = codec->spec;
490 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
491
492 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
493 return 0;
494}
495
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200496static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
497 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498{
499 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
500 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100501 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100503 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100504 hda_nid_t nid = spec->capsrc_nids ?
505 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200506 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
Takashi Iwaicd896c32008-11-18 12:36:33 +0100508 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
509 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100510 if (!imux->num_items && mux_idx > 0)
511 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100512
Takashi Iwaia22d5432009-07-27 12:54:26 +0200513 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200514 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100515 /* Matrix-mixer style (e.g. ALC882) */
516 unsigned int *cur_val = &spec->cur_mux[adc_idx];
517 unsigned int i, idx;
518
519 idx = ucontrol->value.enumerated.item[0];
520 if (idx >= imux->num_items)
521 idx = imux->num_items - 1;
522 if (*cur_val == idx)
523 return 0;
524 for (i = 0; i < imux->num_items; i++) {
525 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
526 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
527 imux->items[i].index,
528 HDA_AMP_MUTE, v);
529 }
530 *cur_val = idx;
531 return 1;
532 } else {
533 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100534 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100535 &spec->cur_mux[adc_idx]);
536 }
537}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200538
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539/*
540 * channel mode setting
541 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200542static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
543 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544{
545 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
546 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100547 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
548 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200551static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
552 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553{
554 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
555 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100556 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200557 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200558 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559}
560
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200561static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563{
564 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
565 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200566 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
567 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200568 &spec->ext_channel_count);
569 if (err >= 0 && !spec->const_channel_count) {
570 spec->multiout.max_channels = spec->ext_channel_count;
571 if (spec->need_dac_fix)
572 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
573 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200574 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100578 * Control the mode of pin widget settings via the mixer. "pc" is used
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300579 * instead of "%" to avoid consequences of accidentally treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100580 * being part of a format specifier. Maximum allowed length of a value is
581 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100582 *
583 * Note: some retasking pin complexes seem to ignore requests for input
584 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
585 * are requested. Therefore order this list so that this behaviour will not
586 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200587 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
588 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200589 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200590static const char * const alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100591 "Mic 50pc bias", "Mic 80pc bias",
592 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100593};
Takashi Iwaia9111322011-05-02 11:30:18 +0200594static const unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100595 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100596};
597/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200598 * in the pin being assumed to be exclusively an input or an output pin. In
599 * addition, "input" pins may or may not process the mic bias option
600 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
601 * accept requests for bias as of chip versions up to March 2006) and/or
602 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100603 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200604#define ALC_PIN_DIR_IN 0x00
605#define ALC_PIN_DIR_OUT 0x01
606#define ALC_PIN_DIR_INOUT 0x02
607#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
608#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100609
Kailang Yangea1fb292008-08-26 12:58:38 +0200610/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100611 * For each direction the minimum and maximum values are given.
612 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200613static const signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100614 { 0, 2 }, /* ALC_PIN_DIR_IN */
615 { 3, 4 }, /* ALC_PIN_DIR_OUT */
616 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200617 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
618 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100619};
620#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
621#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
622#define alc_pin_mode_n_items(_dir) \
623 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
624
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200625static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
626 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200627{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100628 unsigned int item_num = uinfo->value.enumerated.item;
629 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
630
631 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200632 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100633 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
634
635 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
636 item_num = alc_pin_mode_min(dir);
637 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200638 return 0;
639}
640
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200641static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
642 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200643{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100644 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200645 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
646 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100647 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200648 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200649 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
650 AC_VERB_GET_PIN_WIDGET_CONTROL,
651 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200652
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100653 /* Find enumerated value for current pinctl setting */
654 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200655 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100656 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200657 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100658 return 0;
659}
660
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200661static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
662 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100663{
664 signed int change;
665 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
666 hda_nid_t nid = kcontrol->private_value & 0xffff;
667 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
668 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200669 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
670 AC_VERB_GET_PIN_WIDGET_CONTROL,
671 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100672
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200673 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100674 val = alc_pin_mode_min(dir);
675
676 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100677 if (change) {
678 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200679 snd_hda_codec_write_cache(codec, nid, 0,
680 AC_VERB_SET_PIN_WIDGET_CONTROL,
681 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100682
Kailang Yangea1fb292008-08-26 12:58:38 +0200683 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100684 * for the requested pin mode. Enum values of 2 or less are
685 * input modes.
686 *
687 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200688 * reduces noise slightly (particularly on input) so we'll
689 * do it. However, having both input and output buffers
690 * enabled simultaneously doesn't seem to be problematic if
691 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100692 */
693 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200694 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
695 HDA_AMP_MUTE, HDA_AMP_MUTE);
696 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
697 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100698 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200699 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
700 HDA_AMP_MUTE, HDA_AMP_MUTE);
701 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
702 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100703 }
704 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200705 return change;
706}
707
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100708#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200709 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100710 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100711 .info = alc_pin_mode_info, \
712 .get = alc_pin_mode_get, \
713 .put = alc_pin_mode_put, \
714 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100715
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100716/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
717 * together using a mask with more than one bit set. This control is
718 * currently used only by the ALC260 test model. At this stage they are not
719 * needed for any "production" models.
720 */
721#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200722#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200723
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200724static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
725 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100726{
727 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
728 hda_nid_t nid = kcontrol->private_value & 0xffff;
729 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
730 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200731 unsigned int val = snd_hda_codec_read(codec, nid, 0,
732 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100733
734 *valp = (val & mask) != 0;
735 return 0;
736}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200737static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
738 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100739{
740 signed int change;
741 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
742 hda_nid_t nid = kcontrol->private_value & 0xffff;
743 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
744 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200745 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
746 AC_VERB_GET_GPIO_DATA,
747 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100748
749 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200750 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
751 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100752 gpio_data &= ~mask;
753 else
754 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200755 snd_hda_codec_write_cache(codec, nid, 0,
756 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100757
758 return change;
759}
760#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
761 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100762 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100763 .info = alc_gpio_data_info, \
764 .get = alc_gpio_data_get, \
765 .put = alc_gpio_data_put, \
766 .private_value = nid | (mask<<16) }
767#endif /* CONFIG_SND_DEBUG */
768
Jonathan Woithe92621f12006-02-28 11:47:47 +0100769/* A switch control to allow the enabling of the digital IO pins on the
770 * ALC260. This is incredibly simplistic; the intention of this control is
771 * to provide something in the test model allowing digital outputs to be
772 * identified if present. If models are found which can utilise these
773 * outputs a more complete mixer control can be devised for those models if
774 * necessary.
775 */
776#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200777#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200778
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200779static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
780 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100781{
782 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
783 hda_nid_t nid = kcontrol->private_value & 0xffff;
784 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
785 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200786 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100787 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100788
789 *valp = (val & mask) != 0;
790 return 0;
791}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200792static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
793 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100794{
795 signed int change;
796 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
797 hda_nid_t nid = kcontrol->private_value & 0xffff;
798 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
799 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200800 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100801 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200802 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100803
804 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200805 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100806 if (val==0)
807 ctrl_data &= ~mask;
808 else
809 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200810 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
811 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100812
813 return change;
814}
815#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
816 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100817 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100818 .info = alc_spdif_ctrl_info, \
819 .get = alc_spdif_ctrl_get, \
820 .put = alc_spdif_ctrl_put, \
821 .private_value = nid | (mask<<16) }
822#endif /* CONFIG_SND_DEBUG */
823
Jonathan Woithef8225f62008-01-08 12:16:54 +0100824/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
825 * Again, this is only used in the ALC26x test models to help identify when
826 * the EAPD line must be asserted for features to work.
827 */
828#ifdef CONFIG_SND_DEBUG
829#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
830
831static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
832 struct snd_ctl_elem_value *ucontrol)
833{
834 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
835 hda_nid_t nid = kcontrol->private_value & 0xffff;
836 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
837 long *valp = ucontrol->value.integer.value;
838 unsigned int val = snd_hda_codec_read(codec, nid, 0,
839 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
840
841 *valp = (val & mask) != 0;
842 return 0;
843}
844
845static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
846 struct snd_ctl_elem_value *ucontrol)
847{
848 int change;
849 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
850 hda_nid_t nid = kcontrol->private_value & 0xffff;
851 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
852 long val = *ucontrol->value.integer.value;
853 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
854 AC_VERB_GET_EAPD_BTLENABLE,
855 0x00);
856
857 /* Set/unset the masked control bit(s) as needed */
858 change = (!val ? 0 : mask) != (ctrl_data & mask);
859 if (!val)
860 ctrl_data &= ~mask;
861 else
862 ctrl_data |= mask;
863 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
864 ctrl_data);
865
866 return change;
867}
868
869#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
870 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100871 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100872 .info = alc_eapd_ctrl_info, \
873 .get = alc_eapd_ctrl_get, \
874 .put = alc_eapd_ctrl_put, \
875 .private_value = nid | (mask<<16) }
876#endif /* CONFIG_SND_DEBUG */
877
Kailang Yangdf694da2005-12-05 19:42:22 +0100878/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100879 * set up the input pin config (depending on the given auto-pin type)
880 */
881static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
882 int auto_pin_type)
883{
884 unsigned int val = PIN_IN;
885
Takashi Iwai86e29592010-09-09 14:50:17 +0200886 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100887 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200888 unsigned int oldval;
889 oldval = snd_hda_codec_read(codec, nid, 0,
890 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100891 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100892 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200893 /* if the default pin setup is vref50, we give it priority */
894 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100895 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200896 else if (pincap & AC_PINCAP_VREF_50)
897 val = PIN_VREF50;
898 else if (pincap & AC_PINCAP_VREF_100)
899 val = PIN_VREF100;
900 else if (pincap & AC_PINCAP_VREF_GRD)
901 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100902 }
903 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
904}
905
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200906static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
907{
908 struct alc_spec *spec = codec->spec;
909 struct auto_pin_cfg *cfg = &spec->autocfg;
910
911 if (!cfg->line_outs) {
912 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
913 cfg->line_out_pins[cfg->line_outs])
914 cfg->line_outs++;
915 }
916 if (!cfg->speaker_outs) {
917 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
918 cfg->speaker_pins[cfg->speaker_outs])
919 cfg->speaker_outs++;
920 }
921 if (!cfg->hp_outs) {
922 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
923 cfg->hp_pins[cfg->hp_outs])
924 cfg->hp_outs++;
925 }
926}
927
Takashi Iwai23f0c042009-02-26 13:03:58 +0100928/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100929 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200930static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100931{
932 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
933 return;
934 spec->mixers[spec->num_mixers++] = mix;
935}
936
937static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
938{
939 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
940 return;
941 spec->init_verbs[spec->num_init_verbs++] = verb;
942}
943
944/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100945 * set up from the preset table
946 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200947static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200948 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100949{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200950 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100951 int i;
952
953 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100954 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100955 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200956 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
957 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100958 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200959
Kailang Yangdf694da2005-12-05 19:42:22 +0100960 spec->channel_mode = preset->channel_mode;
961 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200962 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200963 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100964
Hector Martin3b315d72009-06-02 10:54:19 +0200965 if (preset->const_channel_count)
966 spec->multiout.max_channels = preset->const_channel_count;
967 else
968 spec->multiout.max_channels = spec->channel_mode[0].channels;
969 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100970
971 spec->multiout.num_dacs = preset->num_dacs;
972 spec->multiout.dac_nids = preset->dac_nids;
973 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800974 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100975 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200976
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200977 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200978 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200979 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100980 spec->input_mux = preset->input_mux;
981
982 spec->num_adc_nids = preset->num_adc_nids;
983 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100984 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100985 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100986
987 spec->unsol_event = preset->unsol_event;
988 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200989#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100990 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200991 spec->loopback.amplist = preset->loopbacks;
992#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200993
994 if (preset->setup)
995 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200996
997 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100998}
999
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001000/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +02001001static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001002 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1003 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1004 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1005 { }
1006};
1007
Takashi Iwaia9111322011-05-02 11:30:18 +02001008static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001009 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1010 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1011 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
1012 { }
1013};
1014
Takashi Iwaia9111322011-05-02 11:30:18 +02001015static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02001016 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
1017 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
1018 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
1019 { }
1020};
1021
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001022/*
1023 * Fix hardware PLL issue
1024 * On some codecs, the analog PLL gating control must be off while
1025 * the default value is 1.
1026 */
1027static void alc_fix_pll(struct hda_codec *codec)
1028{
1029 struct alc_spec *spec = codec->spec;
1030 unsigned int val;
1031
1032 if (!spec->pll_nid)
1033 return;
1034 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1035 spec->pll_coef_idx);
1036 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1037 AC_VERB_GET_PROC_COEF, 0);
1038 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1039 spec->pll_coef_idx);
1040 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1041 val & ~(1 << spec->pll_coef_bit));
1042}
1043
1044static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1045 unsigned int coef_idx, unsigned int coef_bit)
1046{
1047 struct alc_spec *spec = codec->spec;
1048 spec->pll_nid = nid;
1049 spec->pll_coef_idx = coef_idx;
1050 spec->pll_coef_bit = coef_bit;
1051 alc_fix_pll(codec);
1052}
1053
Kailang Yang9ad0e492010-09-14 23:22:00 +02001054static int alc_init_jacks(struct hda_codec *codec)
1055{
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001056#ifdef CONFIG_SND_HDA_INPUT_JACK
Kailang Yang9ad0e492010-09-14 23:22:00 +02001057 struct alc_spec *spec = codec->spec;
1058 int err;
1059 unsigned int hp_nid = spec->autocfg.hp_pins[0];
1060 unsigned int mic_nid = spec->ext_mic.pin;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001061 unsigned int dock_nid = spec->dock_mic.pin;
Kailang Yang9ad0e492010-09-14 23:22:00 +02001062
Takashi Iwai265a0242010-09-21 11:26:21 +02001063 if (hp_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001064 err = snd_hda_input_jack_add(codec, hp_nid,
1065 SND_JACK_HEADPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001066 if (err < 0)
1067 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001068 snd_hda_input_jack_report(codec, hp_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001069 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001070
Takashi Iwai265a0242010-09-21 11:26:21 +02001071 if (mic_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001072 err = snd_hda_input_jack_add(codec, mic_nid,
1073 SND_JACK_MICROPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001074 if (err < 0)
1075 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001076 snd_hda_input_jack_report(codec, mic_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001077 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001078 if (dock_nid) {
1079 err = snd_hda_input_jack_add(codec, dock_nid,
1080 SND_JACK_MICROPHONE, NULL);
1081 if (err < 0)
1082 return err;
1083 snd_hda_input_jack_report(codec, dock_nid);
1084 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001085#endif /* CONFIG_SND_HDA_INPUT_JACK */
Kailang Yang9ad0e492010-09-14 23:22:00 +02001086 return 0;
1087}
Kailang Yang9ad0e492010-09-14 23:22:00 +02001088
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001089static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +02001090{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001091 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +02001092
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001093 for (i = 0; i < num_pins; i++) {
1094 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001095 if (!nid)
1096 break;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001097 snd_hda_input_jack_report(codec, nid);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001098 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001099 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001100 return present;
1101}
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001102
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001103static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +02001104 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001105{
1106 struct alc_spec *spec = codec->spec;
1107 unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02001108 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001109 int i;
1110
1111 for (i = 0; i < num_pins; i++) {
1112 hda_nid_t nid = pins[i];
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001113 if (!nid)
1114 break;
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001115 switch (spec->automute_mode) {
1116 case ALC_AUTOMUTE_PIN:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001117 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001118 AC_VERB_SET_PIN_WIDGET_CONTROL,
1119 pin_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001120 break;
1121 case ALC_AUTOMUTE_AMP:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001122 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001123 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001124 break;
1125 case ALC_AUTOMUTE_MIXER:
1126 nid = spec->automute_mixer_nid[i];
1127 if (!nid)
1128 break;
1129 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001130 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001131 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001132 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001133 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001134 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001135 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001136}
1137
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001138/* Toggle internal speakers muting */
1139static void update_speakers(struct hda_codec *codec)
1140{
1141 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001142 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001143
Takashi Iwaic0a20262011-06-10 15:28:15 +02001144 /* Control HP pins/amps depending on master_mute state;
1145 * in general, HP pins/amps control should be enabled in all cases,
1146 * but currently set only for master_mute, just to be safe
1147 */
1148 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1149 spec->autocfg.hp_pins, spec->master_mute, true);
1150
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001151 if (!spec->automute)
1152 on = 0;
1153 else
1154 on = spec->jack_present | spec->line_jack_present;
1155 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001156 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001157 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001158
1159 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001160 /* if LO is a copy of either HP or Speaker, don't need to handle it */
1161 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
1162 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001163 return;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001164 if (!spec->automute_lines || !spec->automute)
1165 on = 0;
1166 else
1167 on = spec->jack_present;
1168 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001169 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001170 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001171}
1172
1173static void alc_hp_automute(struct hda_codec *codec)
1174{
1175 struct alc_spec *spec = codec->spec;
1176
1177 if (!spec->automute)
1178 return;
1179 spec->jack_present =
1180 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1181 spec->autocfg.hp_pins);
1182 update_speakers(codec);
1183}
1184
1185static void alc_line_automute(struct hda_codec *codec)
1186{
1187 struct alc_spec *spec = codec->spec;
1188
1189 if (!spec->automute || !spec->detect_line)
1190 return;
1191 spec->line_jack_present =
1192 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
1193 spec->autocfg.line_out_pins);
1194 update_speakers(codec);
1195}
1196
Takashi Iwai6c819492009-08-10 18:47:44 +02001197static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
1198 hda_nid_t nid)
1199{
1200 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
1201 int i, nums;
1202
1203 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
1204 for (i = 0; i < nums; i++)
1205 if (conn[i] == nid)
1206 return i;
1207 return -1;
1208}
1209
Takashi Iwai840b64c2010-07-13 22:49:01 +02001210/* switch the current ADC according to the jack state */
1211static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1212{
1213 struct alc_spec *spec = codec->spec;
1214 unsigned int present;
1215 hda_nid_t new_adc;
1216
1217 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1218 if (present)
1219 spec->cur_adc_idx = 1;
1220 else
1221 spec->cur_adc_idx = 0;
1222 new_adc = spec->adc_nids[spec->cur_adc_idx];
1223 if (spec->cur_adc && spec->cur_adc != new_adc) {
1224 /* stream is running, let's swap the current ADC */
Takashi Iwaif0cea792010-08-13 11:56:53 +02001225 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai840b64c2010-07-13 22:49:01 +02001226 spec->cur_adc = new_adc;
1227 snd_hda_codec_setup_stream(codec, new_adc,
1228 spec->cur_adc_stream_tag, 0,
1229 spec->cur_adc_format);
1230 }
1231}
1232
Kailang Yang7fb0d782008-10-15 11:12:35 +02001233static void alc_mic_automute(struct hda_codec *codec)
1234{
1235 struct alc_spec *spec = codec->spec;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001236 struct alc_mic_route *dead1, *dead2, *alive;
Takashi Iwai6c819492009-08-10 18:47:44 +02001237 unsigned int present, type;
1238 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001239
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001240 if (!spec->auto_mic)
1241 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001242 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1243 return;
1244 if (snd_BUG_ON(!spec->adc_nids))
1245 return;
1246
Takashi Iwai840b64c2010-07-13 22:49:01 +02001247 if (spec->dual_adc_switch) {
1248 alc_dual_mic_adc_auto_switch(codec);
1249 return;
1250 }
1251
Takashi Iwai6c819492009-08-10 18:47:44 +02001252 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1253
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001254 alive = &spec->int_mic;
1255 dead1 = &spec->ext_mic;
1256 dead2 = &spec->dock_mic;
1257
Wu Fengguang864f92b2009-11-18 12:38:02 +08001258 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001259 if (present) {
1260 alive = &spec->ext_mic;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001261 dead1 = &spec->int_mic;
1262 dead2 = &spec->dock_mic;
1263 }
1264 if (!present && spec->dock_mic.pin > 0) {
1265 present = snd_hda_jack_detect(codec, spec->dock_mic.pin);
1266 if (present) {
1267 alive = &spec->dock_mic;
1268 dead1 = &spec->int_mic;
1269 dead2 = &spec->ext_mic;
1270 }
1271 snd_hda_input_jack_report(codec, spec->dock_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001272 }
1273
Takashi Iwai6c819492009-08-10 18:47:44 +02001274 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1275 if (type == AC_WID_AUD_MIX) {
1276 /* Matrix-mixer style (e.g. ALC882) */
1277 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1278 alive->mux_idx,
1279 HDA_AMP_MUTE, 0);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001280 if (dead1->pin > 0)
1281 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1282 dead1->mux_idx,
1283 HDA_AMP_MUTE, HDA_AMP_MUTE);
1284 if (dead2->pin > 0)
1285 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1286 dead2->mux_idx,
1287 HDA_AMP_MUTE, HDA_AMP_MUTE);
Takashi Iwai6c819492009-08-10 18:47:44 +02001288 } else {
1289 /* MUX style (e.g. ALC880) */
1290 snd_hda_codec_write_cache(codec, cap_nid, 0,
1291 AC_VERB_SET_CONNECT_SEL,
1292 alive->mux_idx);
1293 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001294 snd_hda_input_jack_report(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001295
1296 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001297}
1298
Kailang Yangc9b58002007-10-16 14:30:01 +02001299/* unsolicited event for HP jack sensing */
1300static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1301{
1302 if (codec->vendor_id == 0x10ec0880)
1303 res >>= 28;
1304 else
1305 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001306 switch (res) {
1307 case ALC880_HP_EVENT:
Takashi Iwaid922b512011-04-28 12:18:53 +02001308 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001309 break;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001310 case ALC880_FRONT_EVENT:
1311 alc_line_automute(codec);
1312 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001313 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001314 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001315 break;
1316 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001317}
1318
1319static void alc_inithook(struct hda_codec *codec)
1320{
Takashi Iwaid922b512011-04-28 12:18:53 +02001321 alc_hp_automute(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001322 alc_line_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001323 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001324}
1325
Kailang Yangf9423e72008-05-27 12:32:25 +02001326/* additional initialization for ALC888 variants */
1327static void alc888_coef_init(struct hda_codec *codec)
1328{
1329 unsigned int tmp;
1330
1331 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1332 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1333 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001334 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001335 /* alc888S-VC */
1336 snd_hda_codec_read(codec, 0x20, 0,
1337 AC_VERB_SET_PROC_COEF, 0x830);
1338 else
1339 /* alc888-VB */
1340 snd_hda_codec_read(codec, 0x20, 0,
1341 AC_VERB_SET_PROC_COEF, 0x3030);
1342}
1343
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001344static void alc889_coef_init(struct hda_codec *codec)
1345{
1346 unsigned int tmp;
1347
1348 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1349 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1350 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1351 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1352}
1353
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001354/* turn on/off EAPD control (only if available) */
1355static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1356{
1357 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1358 return;
1359 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1360 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1361 on ? 2 : 0);
1362}
1363
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001364/* turn on/off EAPD controls of the codec */
1365static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
1366{
1367 /* We currently only handle front, HP */
1368 switch (codec->vendor_id) {
1369 case 0x10ec0260:
1370 set_eapd(codec, 0x0f, on);
1371 set_eapd(codec, 0x10, on);
1372 break;
1373 case 0x10ec0262:
1374 case 0x10ec0267:
1375 case 0x10ec0268:
1376 case 0x10ec0269:
1377 case 0x10ec0270:
1378 case 0x10ec0272:
1379 case 0x10ec0660:
1380 case 0x10ec0662:
1381 case 0x10ec0663:
1382 case 0x10ec0665:
1383 case 0x10ec0862:
1384 case 0x10ec0889:
1385 case 0x10ec0892:
1386 set_eapd(codec, 0x14, on);
1387 set_eapd(codec, 0x15, on);
1388 break;
1389 }
1390}
1391
Takashi Iwai1c716152011-04-07 10:37:16 +02001392/* generic shutup callback;
1393 * just turning off EPAD and a little pause for avoiding pop-noise
1394 */
1395static void alc_eapd_shutup(struct hda_codec *codec)
1396{
1397 alc_auto_setup_eapd(codec, false);
1398 msleep(200);
1399}
1400
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001401static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001402{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001403 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001404
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001405 switch (type) {
1406 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001407 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1408 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001409 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001410 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1411 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001412 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001413 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1414 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001415 case ALC_INIT_DEFAULT:
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001416 alc_auto_setup_eapd(codec, true);
Kailang Yangc9b58002007-10-16 14:30:01 +02001417 switch (codec->vendor_id) {
1418 case 0x10ec0260:
1419 snd_hda_codec_write(codec, 0x1a, 0,
1420 AC_VERB_SET_COEF_INDEX, 7);
1421 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1422 AC_VERB_GET_PROC_COEF, 0);
1423 snd_hda_codec_write(codec, 0x1a, 0,
1424 AC_VERB_SET_COEF_INDEX, 7);
1425 snd_hda_codec_write(codec, 0x1a, 0,
1426 AC_VERB_SET_PROC_COEF,
1427 tmp | 0x2010);
1428 break;
1429 case 0x10ec0262:
1430 case 0x10ec0880:
1431 case 0x10ec0882:
1432 case 0x10ec0883:
1433 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001434 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +01001435 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001436 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001437 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001438 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001439 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001440 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001441#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001442 case 0x10ec0267:
1443 case 0x10ec0268:
1444 snd_hda_codec_write(codec, 0x20, 0,
1445 AC_VERB_SET_COEF_INDEX, 7);
1446 tmp = snd_hda_codec_read(codec, 0x20, 0,
1447 AC_VERB_GET_PROC_COEF, 0);
1448 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001449 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001450 snd_hda_codec_write(codec, 0x20, 0,
1451 AC_VERB_SET_PROC_COEF,
1452 tmp | 0x3000);
1453 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001454#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001455 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001456 break;
1457 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001458}
Kailang Yangea1fb292008-08-26 12:58:38 +02001459
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001460static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
1461 struct snd_ctl_elem_info *uinfo)
1462{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001463 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1464 struct alc_spec *spec = codec->spec;
1465 static const char * const texts2[] = {
1466 "Disabled", "Enabled"
1467 };
1468 static const char * const texts3[] = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001469 "Disabled", "Speaker Only", "Line-Out+Speaker"
1470 };
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001471 const char * const *texts;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001472
1473 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1474 uinfo->count = 1;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001475 if (spec->automute_hp_lo) {
1476 uinfo->value.enumerated.items = 3;
1477 texts = texts3;
1478 } else {
1479 uinfo->value.enumerated.items = 2;
1480 texts = texts2;
1481 }
1482 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1483 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001484 strcpy(uinfo->value.enumerated.name,
1485 texts[uinfo->value.enumerated.item]);
1486 return 0;
1487}
1488
1489static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
1490 struct snd_ctl_elem_value *ucontrol)
1491{
1492 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1493 struct alc_spec *spec = codec->spec;
1494 unsigned int val;
1495 if (!spec->automute)
1496 val = 0;
1497 else if (!spec->automute_lines)
1498 val = 1;
1499 else
1500 val = 2;
1501 ucontrol->value.enumerated.item[0] = val;
1502 return 0;
1503}
1504
1505static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
1506 struct snd_ctl_elem_value *ucontrol)
1507{
1508 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1509 struct alc_spec *spec = codec->spec;
1510
1511 switch (ucontrol->value.enumerated.item[0]) {
1512 case 0:
1513 if (!spec->automute)
1514 return 0;
1515 spec->automute = 0;
1516 break;
1517 case 1:
1518 if (spec->automute && !spec->automute_lines)
1519 return 0;
1520 spec->automute = 1;
1521 spec->automute_lines = 0;
1522 break;
1523 case 2:
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001524 if (!spec->automute_hp_lo)
1525 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001526 if (spec->automute && spec->automute_lines)
1527 return 0;
1528 spec->automute = 1;
1529 spec->automute_lines = 1;
1530 break;
1531 default:
1532 return -EINVAL;
1533 }
1534 update_speakers(codec);
1535 return 1;
1536}
1537
Takashi Iwaia9111322011-05-02 11:30:18 +02001538static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001539 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1540 .name = "Auto-Mute Mode",
1541 .info = alc_automute_mode_info,
1542 .get = alc_automute_mode_get,
1543 .put = alc_automute_mode_put,
1544};
1545
1546static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
1547
1548static int alc_add_automute_mode_enum(struct hda_codec *codec)
1549{
1550 struct alc_spec *spec = codec->spec;
1551 struct snd_kcontrol_new *knew;
1552
1553 knew = alc_kcontrol_new(spec);
1554 if (!knew)
1555 return -ENOMEM;
1556 *knew = alc_automute_mode_enum;
1557 knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
1558 if (!knew->name)
1559 return -ENOMEM;
1560 return 0;
1561}
1562
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001563static void alc_init_auto_hp(struct hda_codec *codec)
1564{
1565 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001566 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001567 int present = 0;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001568 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001569
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001570 if (cfg->hp_pins[0])
1571 present++;
1572 if (cfg->line_out_pins[0])
1573 present++;
1574 if (cfg->speaker_pins[0])
1575 present++;
1576 if (present < 2) /* need two different output types */
1577 return;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001578 if (present == 3)
1579 spec->automute_hp_lo = 1; /* both HP and LO automute */
Kailang Yangc9b58002007-10-16 14:30:01 +02001580
Takashi Iwaicb1d0a12011-07-27 16:41:57 +02001581 if (!cfg->speaker_pins[0] &&
1582 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001583 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1584 sizeof(cfg->speaker_pins));
1585 cfg->speaker_outs = cfg->line_outs;
1586 }
1587
Takashi Iwaicb1d0a12011-07-27 16:41:57 +02001588 if (!cfg->hp_pins[0] &&
1589 cfg->line_out_type == AUTO_PIN_HP_OUT) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001590 memcpy(cfg->hp_pins, cfg->line_out_pins,
1591 sizeof(cfg->hp_pins));
1592 cfg->hp_outs = cfg->line_outs;
1593 }
1594
1595 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001596 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001597 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001598 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001599 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001600 nid);
1601 snd_hda_codec_write_cache(codec, nid, 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001602 AC_VERB_SET_UNSOLICITED_ENABLE,
1603 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaid922b512011-04-28 12:18:53 +02001604 spec->automute = 1;
1605 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001606 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001607 if (spec->automute && cfg->line_out_pins[0] &&
Takashi Iwaicb1d0a12011-07-27 16:41:57 +02001608 cfg->speaker_pins[0] &&
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001609 cfg->line_out_pins[0] != cfg->hp_pins[0] &&
1610 cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
1611 for (i = 0; i < cfg->line_outs; i++) {
1612 hda_nid_t nid = cfg->line_out_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001613 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001614 continue;
1615 snd_printdd("realtek: Enable Line-Out auto-muting "
1616 "on NID 0x%x\n", nid);
1617 snd_hda_codec_write_cache(codec, nid, 0,
1618 AC_VERB_SET_UNSOLICITED_ENABLE,
1619 AC_USRSP_EN | ALC880_FRONT_EVENT);
1620 spec->detect_line = 1;
1621 }
Takashi Iwai52d3cb82011-05-17 10:04:08 +02001622 spec->automute_lines = spec->detect_line;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001623 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001624
1625 if (spec->automute) {
1626 /* create a control for automute mode */
1627 alc_add_automute_mode_enum(codec);
1628 spec->unsol_event = alc_sku_unsol_event;
1629 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001630}
1631
Takashi Iwai6c819492009-08-10 18:47:44 +02001632static void alc_init_auto_mic(struct hda_codec *codec)
1633{
1634 struct alc_spec *spec = codec->spec;
1635 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001636 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001637 int i;
1638
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001639 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001640 for (i = 0; i < cfg->num_inputs; i++) {
1641 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001642 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001643 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001644 switch (snd_hda_get_input_pin_attr(defcfg)) {
1645 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001646 if (fixed)
1647 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001648 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1649 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001650 fixed = nid;
1651 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001652 case INPUT_PIN_ATTR_UNUSED:
1653 return; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001654 case INPUT_PIN_ATTR_DOCK:
1655 if (dock)
1656 return; /* already occupied */
1657 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
1658 return; /* invalid type */
1659 dock = nid;
1660 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001661 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001662 if (ext)
1663 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001664 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1665 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001666 ext = nid;
1667 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001668 }
1669 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001670 if (!ext && dock) {
1671 ext = dock;
1672 dock = 0;
1673 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001674 if (!ext || !fixed)
1675 return;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001676 if (!is_jack_detectable(codec, ext))
Takashi Iwai6c819492009-08-10 18:47:44 +02001677 return; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001678 if (dock && !is_jack_detectable(codec, dock))
1679 return; /* no unsol support */
1680 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1681 ext, fixed, dock);
Takashi Iwai6c819492009-08-10 18:47:44 +02001682 spec->ext_mic.pin = ext;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001683 spec->dock_mic.pin = dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001684 spec->int_mic.pin = fixed;
1685 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001686 spec->dock_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
Takashi Iwai6c819492009-08-10 18:47:44 +02001687 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1688 spec->auto_mic = 1;
1689 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1690 AC_VERB_SET_UNSOLICITED_ENABLE,
1691 AC_USRSP_EN | ALC880_MIC_EVENT);
1692 spec->unsol_event = alc_sku_unsol_event;
1693}
1694
David Henningsson90622912010-10-14 14:50:18 +02001695/* Could be any non-zero and even value. When used as fixup, tells
1696 * the driver to ignore any present sku defines.
1697 */
1698#define ALC_FIXUP_SKU_IGNORE (2)
1699
Kailang Yangda00c242010-03-19 11:23:45 +01001700static int alc_auto_parse_customize_define(struct hda_codec *codec)
1701{
1702 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001703 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001704 struct alc_spec *spec = codec->spec;
1705
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001706 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1707
David Henningsson90622912010-10-14 14:50:18 +02001708 if (spec->cdefine.fixup) {
1709 ass = spec->cdefine.sku_cfg;
1710 if (ass == ALC_FIXUP_SKU_IGNORE)
1711 return -1;
1712 goto do_sku;
1713 }
1714
Kailang Yangda00c242010-03-19 11:23:45 +01001715 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001716 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001717 goto do_sku;
1718
1719 nid = 0x1d;
1720 if (codec->vendor_id == 0x10ec0260)
1721 nid = 0x17;
1722 ass = snd_hda_codec_get_pincfg(codec, nid);
1723
1724 if (!(ass & 1)) {
1725 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1726 codec->chip_name, ass);
1727 return -1;
1728 }
1729
1730 /* check sum */
1731 tmp = 0;
1732 for (i = 1; i < 16; i++) {
1733 if ((ass >> i) & 1)
1734 tmp++;
1735 }
1736 if (((ass >> 16) & 0xf) != tmp)
1737 return -1;
1738
1739 spec->cdefine.port_connectivity = ass >> 30;
1740 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1741 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1742 spec->cdefine.customization = ass >> 8;
1743do_sku:
1744 spec->cdefine.sku_cfg = ass;
1745 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1746 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1747 spec->cdefine.swap = (ass & 0x2) >> 1;
1748 spec->cdefine.override = ass & 0x1;
1749
1750 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1751 nid, spec->cdefine.sku_cfg);
1752 snd_printd("SKU: port_connectivity=0x%x\n",
1753 spec->cdefine.port_connectivity);
1754 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1755 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1756 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1757 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1758 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1759 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1760 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1761
1762 return 0;
1763}
1764
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001765/* check subsystem ID and set up device-specific initialization;
1766 * return 1 if initialized, 0 if invalid SSID
1767 */
1768/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1769 * 31 ~ 16 : Manufacture ID
1770 * 15 ~ 8 : SKU ID
1771 * 7 ~ 0 : Assembly ID
1772 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1773 */
1774static int alc_subsystem_id(struct hda_codec *codec,
1775 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001776 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001777{
1778 unsigned int ass, tmp, i;
1779 unsigned nid;
1780 struct alc_spec *spec = codec->spec;
1781
David Henningsson90622912010-10-14 14:50:18 +02001782 if (spec->cdefine.fixup) {
1783 ass = spec->cdefine.sku_cfg;
1784 if (ass == ALC_FIXUP_SKU_IGNORE)
1785 return 0;
1786 goto do_sku;
1787 }
1788
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001789 ass = codec->subsystem_id & 0xffff;
1790 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1791 goto do_sku;
1792
1793 /* invalid SSID, check the special NID pin defcfg instead */
1794 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001795 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001796 * 29~21 : reserve
1797 * 20 : PCBEEP input
1798 * 19~16 : Check sum (15:1)
1799 * 15~1 : Custom
1800 * 0 : override
1801 */
1802 nid = 0x1d;
1803 if (codec->vendor_id == 0x10ec0260)
1804 nid = 0x17;
1805 ass = snd_hda_codec_get_pincfg(codec, nid);
1806 snd_printd("realtek: No valid SSID, "
1807 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001808 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001809 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001810 return 0;
1811 if ((ass >> 30) != 1) /* no physical connection */
1812 return 0;
1813
1814 /* check sum */
1815 tmp = 0;
1816 for (i = 1; i < 16; i++) {
1817 if ((ass >> i) & 1)
1818 tmp++;
1819 }
1820 if (((ass >> 16) & 0xf) != tmp)
1821 return 0;
1822do_sku:
1823 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1824 ass & 0xffff, codec->vendor_id);
1825 /*
1826 * 0 : override
1827 * 1 : Swap Jack
1828 * 2 : 0 --> Desktop, 1 --> Laptop
1829 * 3~5 : External Amplifier control
1830 * 7~6 : Reserved
1831 */
1832 tmp = (ass & 0x38) >> 3; /* external Amp control */
1833 switch (tmp) {
1834 case 1:
1835 spec->init_amp = ALC_INIT_GPIO1;
1836 break;
1837 case 3:
1838 spec->init_amp = ALC_INIT_GPIO2;
1839 break;
1840 case 7:
1841 spec->init_amp = ALC_INIT_GPIO3;
1842 break;
1843 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001844 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001845 spec->init_amp = ALC_INIT_DEFAULT;
1846 break;
1847 }
1848
1849 /* is laptop or Desktop and enable the function "Mute internal speaker
1850 * when the external headphone out jack is plugged"
1851 */
1852 if (!(ass & 0x8000))
1853 return 1;
1854 /*
1855 * 10~8 : Jack location
1856 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1857 * 14~13: Resvered
1858 * 15 : 1 --> enable the function "Mute internal speaker
1859 * when the external headphone out jack is plugged"
1860 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001861 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001862 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001863 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1864 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001865 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001866 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001867 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001868 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001869 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001870 else if (tmp == 3)
1871 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001872 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001873 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001874 for (i = 0; i < spec->autocfg.line_outs; i++)
1875 if (spec->autocfg.line_out_pins[i] == nid)
1876 return 1;
1877 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001878 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001879 return 1;
1880}
Kailang Yangea1fb292008-08-26 12:58:38 +02001881
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001882static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001883 hda_nid_t porta, hda_nid_t porte,
1884 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001885{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001886 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001887 struct alc_spec *spec = codec->spec;
1888 snd_printd("realtek: "
1889 "Enable default setup for auto mode as fallback\n");
1890 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001891 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001892
1893 alc_init_auto_hp(codec);
1894 alc_init_auto_mic(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001895}
1896
Takashi Iwai41e41f12005-06-08 14:48:49 +02001897/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001898 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001899 */
1900
1901struct alc_pincfg {
1902 hda_nid_t nid;
1903 u32 val;
1904};
1905
Todd Broche1eb5f12010-12-06 11:19:51 -08001906struct alc_model_fixup {
1907 const int id;
1908 const char *name;
1909};
1910
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001911struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001912 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001913 bool chained;
1914 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001915 union {
1916 unsigned int sku;
1917 const struct alc_pincfg *pins;
1918 const struct hda_verb *verbs;
1919 void (*func)(struct hda_codec *codec,
1920 const struct alc_fixup *fix,
1921 int action);
1922 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001923};
1924
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001925enum {
1926 ALC_FIXUP_INVALID,
1927 ALC_FIXUP_SKU,
1928 ALC_FIXUP_PINS,
1929 ALC_FIXUP_VERBS,
1930 ALC_FIXUP_FUNC,
1931};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001932
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001933enum {
1934 ALC_FIXUP_ACT_PRE_PROBE,
1935 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001936 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001937};
1938
1939static void alc_apply_fixup(struct hda_codec *codec, int action)
1940{
1941 struct alc_spec *spec = codec->spec;
1942 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001943#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001944 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001945#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001946 int depth = 0;
1947
1948 if (!spec->fixup_list)
1949 return;
1950
1951 while (id >= 0) {
1952 const struct alc_fixup *fix = spec->fixup_list + id;
1953 const struct alc_pincfg *cfg;
1954
1955 switch (fix->type) {
1956 case ALC_FIXUP_SKU:
1957 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
1958 break;;
1959 snd_printdd(KERN_INFO "hda_codec: %s: "
1960 "Apply sku override for %s\n",
1961 codec->chip_name, modelname);
1962 spec->cdefine.sku_cfg = fix->v.sku;
1963 spec->cdefine.fixup = 1;
1964 break;
1965 case ALC_FIXUP_PINS:
1966 cfg = fix->v.pins;
1967 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1968 break;
1969 snd_printdd(KERN_INFO "hda_codec: %s: "
1970 "Apply pincfg for %s\n",
1971 codec->chip_name, modelname);
1972 for (; cfg->nid; cfg++)
1973 snd_hda_codec_set_pincfg(codec, cfg->nid,
1974 cfg->val);
1975 break;
1976 case ALC_FIXUP_VERBS:
1977 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
1978 break;
1979 snd_printdd(KERN_INFO "hda_codec: %s: "
1980 "Apply fix-verbs for %s\n",
1981 codec->chip_name, modelname);
1982 add_verb(codec->spec, fix->v.verbs);
1983 break;
1984 case ALC_FIXUP_FUNC:
1985 if (!fix->v.func)
1986 break;
1987 snd_printdd(KERN_INFO "hda_codec: %s: "
1988 "Apply fix-func for %s\n",
1989 codec->chip_name, modelname);
1990 fix->v.func(codec, fix, action);
1991 break;
1992 default:
1993 snd_printk(KERN_ERR "hda_codec: %s: "
1994 "Invalid fixup type %d\n",
1995 codec->chip_name, fix->type);
1996 break;
1997 }
Takashi Iwai24af2b12011-05-02 13:55:36 +02001998 if (!fix->chained)
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001999 break;
2000 if (++depth > 10)
2001 break;
Takashi Iwai24af2b12011-05-02 13:55:36 +02002002 id = fix->chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01002003 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002004}
2005
Todd Broche1eb5f12010-12-06 11:19:51 -08002006static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002007 const struct alc_model_fixup *models,
2008 const struct snd_pci_quirk *quirk,
2009 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08002010{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002011 struct alc_spec *spec = codec->spec;
2012 int id = -1;
2013 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08002014
Todd Broche1eb5f12010-12-06 11:19:51 -08002015 if (codec->modelname && models) {
2016 while (models->name) {
2017 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002018 id = models->id;
2019 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002020 break;
2021 }
2022 models++;
2023 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002024 }
2025 if (id < 0) {
2026 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
2027 if (quirk) {
2028 id = quirk->value;
2029#ifdef CONFIG_SND_DEBUG_VERBOSE
2030 name = quirk->name;
2031#endif
2032 }
2033 }
2034
2035 spec->fixup_id = id;
2036 if (id >= 0) {
2037 spec->fixup_list = fixlist;
2038 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002039 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002040}
2041
Kailang Yang274693f2009-12-03 10:07:50 +01002042static int alc_read_coef_idx(struct hda_codec *codec,
2043 unsigned int coef_idx)
2044{
2045 unsigned int val;
2046 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2047 coef_idx);
2048 val = snd_hda_codec_read(codec, 0x20, 0,
2049 AC_VERB_GET_PROC_COEF, 0);
2050 return val;
2051}
2052
Kailang Yang977ddd62010-09-15 10:02:29 +02002053static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
2054 unsigned int coef_val)
2055{
2056 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2057 coef_idx);
2058 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
2059 coef_val);
2060}
2061
Takashi Iwai757899a2010-07-30 10:48:14 +02002062/* set right pin controls for digital I/O */
2063static void alc_auto_init_digital(struct hda_codec *codec)
2064{
2065 struct alc_spec *spec = codec->spec;
2066 int i;
2067 hda_nid_t pin;
2068
2069 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2070 pin = spec->autocfg.dig_out_pins[i];
2071 if (pin) {
2072 snd_hda_codec_write(codec, pin, 0,
2073 AC_VERB_SET_PIN_WIDGET_CONTROL,
2074 PIN_OUT);
2075 }
2076 }
2077 pin = spec->autocfg.dig_in_pin;
2078 if (pin)
2079 snd_hda_codec_write(codec, pin, 0,
2080 AC_VERB_SET_PIN_WIDGET_CONTROL,
2081 PIN_IN);
2082}
2083
2084/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
2085static void alc_auto_parse_digital(struct hda_codec *codec)
2086{
2087 struct alc_spec *spec = codec->spec;
2088 int i, err;
2089 hda_nid_t dig_nid;
2090
2091 /* support multiple SPDIFs; the secondary is set up as a slave */
2092 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2093 err = snd_hda_get_connections(codec,
2094 spec->autocfg.dig_out_pins[i],
2095 &dig_nid, 1);
2096 if (err < 0)
2097 continue;
2098 if (!i) {
2099 spec->multiout.dig_out_nid = dig_nid;
2100 spec->dig_out_type = spec->autocfg.dig_out_type[0];
2101 } else {
2102 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
2103 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
2104 break;
2105 spec->slave_dig_outs[i - 1] = dig_nid;
2106 }
2107 }
2108
2109 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02002110 dig_nid = codec->start_nid;
2111 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
2112 unsigned int wcaps = get_wcaps(codec, dig_nid);
2113 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
2114 continue;
2115 if (!(wcaps & AC_WCAP_DIGITAL))
2116 continue;
2117 if (!(wcaps & AC_WCAP_CONN_LIST))
2118 continue;
2119 err = get_connection_index(codec, dig_nid,
2120 spec->autocfg.dig_in_pin);
2121 if (err >= 0) {
2122 spec->dig_in_nid = dig_nid;
2123 break;
2124 }
2125 }
Takashi Iwai757899a2010-07-30 10:48:14 +02002126 }
2127}
2128
Takashi Iwaif95474e2007-07-10 00:47:43 +02002129/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002130 * ALC888
2131 */
2132
2133/*
2134 * 2ch mode
2135 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002136static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002137/* Mic-in jack as mic in */
2138 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2139 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2140/* Line-in jack as Line in */
2141 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2142 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2143/* Line-Out as Front */
2144 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2145 { } /* end */
2146};
2147
2148/*
2149 * 4ch mode
2150 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002151static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002152/* Mic-in jack as mic in */
2153 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2154 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2155/* Line-in jack as Surround */
2156 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2157 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2158/* Line-Out as Front */
2159 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2160 { } /* end */
2161};
2162
2163/*
2164 * 6ch mode
2165 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002166static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002167/* Mic-in jack as CLFE */
2168 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2169 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2170/* Line-in jack as Surround */
2171 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2172 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2173/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
2174 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2175 { } /* end */
2176};
2177
2178/*
2179 * 8ch mode
2180 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002181static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002182/* Mic-in jack as CLFE */
2183 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2184 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2185/* Line-in jack as Surround */
2186 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2187 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2188/* Line-Out as Side */
2189 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2190 { } /* end */
2191};
2192
Takashi Iwaia9111322011-05-02 11:30:18 +02002193static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002194 { 2, alc888_4ST_ch2_intel_init },
2195 { 4, alc888_4ST_ch4_intel_init },
2196 { 6, alc888_4ST_ch6_intel_init },
2197 { 8, alc888_4ST_ch8_intel_init },
2198};
2199
2200/*
2201 * ALC888 Fujitsu Siemens Amillo xa3530
2202 */
2203
Takashi Iwaia9111322011-05-02 11:30:18 +02002204static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002205/* Front Mic: set to PIN_IN (empty by default) */
2206 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2207/* Connect Internal HP to Front */
2208 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2209 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2210 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2211/* Connect Bass HP to Front */
2212 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2213 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2214 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2215/* Connect Line-Out side jack (SPDIF) to Side */
2216 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2217 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2218 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2219/* Connect Mic jack to CLFE */
2220 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2221 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2222 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
2223/* Connect Line-in jack to Surround */
2224 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2225 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2226 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
2227/* Connect HP out jack to Front */
2228 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2229 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2230 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2231/* Enable unsolicited event for HP jack and Line-out jack */
2232 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2233 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2234 {}
2235};
2236
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002237static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02002238{
2239 struct alc_spec *spec = codec->spec;
2240
2241 spec->autocfg.hp_pins[0] = 0x15;
2242 spec->autocfg.speaker_pins[0] = 0x14;
2243 spec->autocfg.speaker_pins[1] = 0x16;
2244 spec->autocfg.speaker_pins[2] = 0x17;
2245 spec->autocfg.speaker_pins[3] = 0x19;
2246 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02002247 spec->automute = 1;
2248 spec->automute_mode = ALC_AUTOMUTE_AMP;
Wu Fengguang6732bd02009-07-30 09:19:14 +02002249}
2250
2251static void alc889_intel_init_hook(struct hda_codec *codec)
2252{
2253 alc889_coef_init(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02002254 alc_hp_automute(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02002255}
2256
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002257static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002258{
2259 struct alc_spec *spec = codec->spec;
2260
2261 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
2262 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
2263 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
2264 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaid922b512011-04-28 12:18:53 +02002265 spec->automute = 1;
2266 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002267}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002268
2269/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002270 * ALC888 Acer Aspire 4930G model
2271 */
2272
Takashi Iwaia9111322011-05-02 11:30:18 +02002273static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002274/* Front Mic: set to PIN_IN (empty by default) */
2275 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2276/* Unselect Front Mic by default in input mixer 3 */
2277 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002278/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002279 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2280/* Connect Internal HP to front */
2281 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2282 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2283 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2284/* Connect HP out to front */
2285 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2286 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2287 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie2e93292011-01-12 08:03:39 +01002288 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002289 { }
2290};
2291
Hector Martin3b315d72009-06-02 10:54:19 +02002292/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01002293 * ALC888 Acer Aspire 6530G model
2294 */
2295
Takashi Iwaia9111322011-05-02 11:30:18 +02002296static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01002297/* Route to built-in subwoofer as well as speakers */
2298 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2299 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2300 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2301 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002302/* Bias voltage on for external mic port */
2303 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02002304/* Front Mic: set to PIN_IN (empty by default) */
2305 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2306/* Unselect Front Mic by default in input mixer 3 */
2307 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002308/* Enable unsolicited event for HP jack */
2309 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2310/* Enable speaker output */
2311 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2312 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01002313 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002314/* Enable headphone output */
2315 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2316 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2317 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01002318 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002319 { }
2320};
2321
2322/*
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002323 *ALC888 Acer Aspire 7730G model
2324 */
2325
Takashi Iwaia9111322011-05-02 11:30:18 +02002326static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002327/* Bias voltage on for external mic port */
2328 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
2329/* Front Mic: set to PIN_IN (empty by default) */
2330 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2331/* Unselect Front Mic by default in input mixer 3 */
2332 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2333/* Enable unsolicited event for HP jack */
2334 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2335/* Enable speaker output */
2336 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2337 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2338 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
2339/* Enable headphone output */
2340 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2341 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2342 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2343 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
2344/*Enable internal subwoofer */
2345 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2346 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2347 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
2348 {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
2349 { }
2350};
2351
2352/*
Hector Martin018df412009-06-04 00:13:40 +02002353 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02002354 */
2355
Takashi Iwaia9111322011-05-02 11:30:18 +02002356static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02002357/* Front Mic: set to PIN_IN (empty by default) */
2358 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2359/* Unselect Front Mic by default in input mixer 3 */
2360 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2361/* Enable unsolicited event for HP jack */
2362 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2363/* Connect Internal Front to Front */
2364 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2365 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2366 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2367/* Connect Internal Rear to Rear */
2368 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2369 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2370 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2371/* Connect Internal CLFE to CLFE */
2372 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2373 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2374 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2375/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002376 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002377 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2378 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2379/* Enable all DACs */
2380/* DAC DISABLE/MUTE 1? */
2381/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2382 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2383 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2384/* DAC DISABLE/MUTE 2? */
2385/* some bit here disables the other DACs. Init=0x4900 */
2386 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2387 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002388/* DMIC fix
2389 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2390 * which makes the stereo useless. However, either the mic or the ALC889
2391 * makes the signal become a difference/sum signal instead of standard
2392 * stereo, which is annoying. So instead we flip this bit which makes the
2393 * codec replicate the sum signal to both channels, turning it into a
2394 * normal mono mic.
2395 */
2396/* DMIC_CONTROL? Init value = 0x0001 */
2397 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2398 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002399 { }
2400};
2401
Takashi Iwaia9111322011-05-02 11:30:18 +02002402static const struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002403 /* Front mic only available on one ADC */
2404 {
2405 .num_items = 4,
2406 .items = {
2407 { "Mic", 0x0 },
2408 { "Line", 0x2 },
2409 { "CD", 0x4 },
2410 { "Front Mic", 0xb },
2411 },
2412 },
2413 {
2414 .num_items = 3,
2415 .items = {
2416 { "Mic", 0x0 },
2417 { "Line", 0x2 },
2418 { "CD", 0x4 },
2419 },
2420 }
2421};
2422
Takashi Iwaia9111322011-05-02 11:30:18 +02002423static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01002424 /* Interal mic only available on one ADC */
2425 {
Tony Vroon684a8842009-06-26 09:27:50 +01002426 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002427 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002428 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002429 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002430 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002431 { "Input Mix", 0xa },
David Henningsson28c4edb2010-12-20 14:24:29 +01002432 { "Internal Mic", 0xb },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002433 },
2434 },
2435 {
Tony Vroon684a8842009-06-26 09:27:50 +01002436 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002437 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002438 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002439 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002440 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002441 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002442 },
2443 }
2444};
2445
Takashi Iwaia9111322011-05-02 11:30:18 +02002446static const struct hda_input_mux alc889_capture_sources[3] = {
Hector Martin018df412009-06-04 00:13:40 +02002447 /* Digital mic only available on first "ADC" */
2448 {
2449 .num_items = 5,
2450 .items = {
2451 { "Mic", 0x0 },
2452 { "Line", 0x2 },
2453 { "CD", 0x4 },
2454 { "Front Mic", 0xb },
2455 { "Input Mix", 0xa },
2456 },
2457 },
2458 {
2459 .num_items = 4,
2460 .items = {
2461 { "Mic", 0x0 },
2462 { "Line", 0x2 },
2463 { "CD", 0x4 },
2464 { "Input Mix", 0xa },
2465 },
2466 },
2467 {
2468 .num_items = 4,
2469 .items = {
2470 { "Mic", 0x0 },
2471 { "Line", 0x2 },
2472 { "CD", 0x4 },
2473 { "Input Mix", 0xa },
2474 },
2475 }
2476};
2477
Takashi Iwaia9111322011-05-02 11:30:18 +02002478static const struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002479 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2480 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2481 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2482 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2483 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2484 HDA_OUTPUT),
2485 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2486 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2487 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2488 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2489 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2490 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2491 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2492 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2493 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2494 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002495 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002496 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002497 { } /* end */
2498};
2499
Takashi Iwaia9111322011-05-02 11:30:18 +02002500static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002501 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2502 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2503 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2504 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002505 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002506 HDA_OUTPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002507 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2508 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2509 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2510 HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
2511 HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002512 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2513 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2514 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2515 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2516 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2517 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
2518 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2519 { } /* end */
2520};
2521
Takashi Iwaia9111322011-05-02 11:30:18 +02002522static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
Hector Martin556eea92009-12-20 22:51:23 +01002523 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2524 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2525 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2526 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2527 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2528 HDA_OUTPUT),
2529 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2530 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2531 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2532 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2533 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2534 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002535 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002536 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2537 { } /* end */
2538};
2539
2540
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002541static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002542{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002543 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002544
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002545 spec->autocfg.hp_pins[0] = 0x15;
2546 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002547 spec->autocfg.speaker_pins[1] = 0x16;
2548 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002549 spec->automute = 1;
2550 spec->automute_mode = ALC_AUTOMUTE_AMP;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002551}
2552
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002553static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002554{
2555 struct alc_spec *spec = codec->spec;
2556
2557 spec->autocfg.hp_pins[0] = 0x15;
2558 spec->autocfg.speaker_pins[0] = 0x14;
2559 spec->autocfg.speaker_pins[1] = 0x16;
2560 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002561 spec->automute = 1;
2562 spec->automute_mode = ALC_AUTOMUTE_AMP;
Emilio López320d5922009-06-25 08:18:44 +02002563}
2564
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002565static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2566{
2567 struct alc_spec *spec = codec->spec;
2568
2569 spec->autocfg.hp_pins[0] = 0x15;
2570 spec->autocfg.speaker_pins[0] = 0x14;
2571 spec->autocfg.speaker_pins[1] = 0x16;
2572 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002573 spec->automute = 1;
2574 spec->automute_mode = ALC_AUTOMUTE_AMP;
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002575}
2576
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002577static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002578{
2579 struct alc_spec *spec = codec->spec;
2580
2581 spec->autocfg.hp_pins[0] = 0x15;
2582 spec->autocfg.speaker_pins[0] = 0x14;
2583 spec->autocfg.speaker_pins[1] = 0x16;
2584 spec->autocfg.speaker_pins[2] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02002585 spec->automute = 1;
2586 spec->automute_mode = ALC_AUTOMUTE_AMP;
Hector Martin3b315d72009-06-02 10:54:19 +02002587}
2588
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002589/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002590 * ALC880 3-stack model
2591 *
2592 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002593 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2594 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 */
2596
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002597static const hda_nid_t alc880_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002598 /* front, rear, clfe, rear_surr */
2599 0x02, 0x05, 0x04, 0x03
2600};
2601
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002602static const hda_nid_t alc880_adc_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002603 /* ADC0-2 */
2604 0x07, 0x08, 0x09,
2605};
2606
2607/* The datasheet says the node 0x07 is connected from inputs,
2608 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002609 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002611static const hda_nid_t alc880_adc_nids_alt[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002612 /* ADC1-2 */
2613 0x08, 0x09,
2614};
2615
2616#define ALC880_DIGOUT_NID 0x06
2617#define ALC880_DIGIN_NID 0x0a
2618
Takashi Iwaia9111322011-05-02 11:30:18 +02002619static const struct hda_input_mux alc880_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002620 .num_items = 4,
2621 .items = {
2622 { "Mic", 0x0 },
2623 { "Front Mic", 0x3 },
2624 { "Line", 0x2 },
2625 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002627};
2628
2629/* channel source setting (2/6 channel selection for 3-stack) */
2630/* 2ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002631static const struct hda_verb alc880_threestack_ch2_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002632 /* set line-in to input, mute it */
2633 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2634 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2635 /* set mic-in to input vref 80%, mute it */
2636 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2637 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 { } /* end */
2639};
2640
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002641/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002642static const struct hda_verb alc880_threestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002643 /* set line-in to output, unmute it */
2644 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2645 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2646 /* set mic-in to output, unmute it */
2647 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2648 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2649 { } /* end */
2650};
2651
Takashi Iwaia9111322011-05-02 11:30:18 +02002652static const struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002653 { 2, alc880_threestack_ch2_init },
2654 { 6, alc880_threestack_ch6_init },
2655};
2656
Takashi Iwaia9111322011-05-02 11:30:18 +02002657static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002658 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002659 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002660 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002661 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002662 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2663 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002664 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2665 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2667 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2668 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2669 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2670 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2671 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2672 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2673 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002675 {
2676 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2677 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002678 .info = alc_ch_mode_info,
2679 .get = alc_ch_mode_get,
2680 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002681 },
2682 { } /* end */
2683};
2684
2685/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002686static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2687 struct snd_ctl_elem_info *uinfo)
2688{
2689 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2690 struct alc_spec *spec = codec->spec;
2691 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002692
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002693 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002694 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2695 HDA_INPUT);
2696 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002697 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002698 return err;
2699}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002701static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2702 unsigned int size, unsigned int __user *tlv)
2703{
2704 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2705 struct alc_spec *spec = codec->spec;
2706 int err;
2707
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002708 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002709 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2710 HDA_INPUT);
2711 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002712 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002713 return err;
2714}
2715
2716typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2717 struct snd_ctl_elem_value *ucontrol);
2718
2719static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2720 struct snd_ctl_elem_value *ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002721 getput_call_t func, bool check_adc_switch)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002722{
2723 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2724 struct alc_spec *spec = codec->spec;
Takashi Iwaiabaead62011-07-09 11:55:28 +02002725 int i, err = 0;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002726
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002727 mutex_lock(&codec->control_mutex);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002728 if (check_adc_switch && spec->dual_adc_switch) {
2729 for (i = 0; i < spec->num_adc_nids; i++) {
2730 kcontrol->private_value =
2731 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2732 3, 0, HDA_INPUT);
2733 err = func(kcontrol, ucontrol);
2734 if (err < 0)
2735 goto error;
2736 }
2737 } else {
2738 i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2739 kcontrol->private_value =
2740 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2741 3, 0, HDA_INPUT);
2742 err = func(kcontrol, ucontrol);
2743 }
2744 error:
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002745 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002746 return err;
2747}
2748
2749static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2750 struct snd_ctl_elem_value *ucontrol)
2751{
2752 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002753 snd_hda_mixer_amp_volume_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002754}
2755
2756static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2757 struct snd_ctl_elem_value *ucontrol)
2758{
2759 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002760 snd_hda_mixer_amp_volume_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002761}
2762
2763/* capture mixer elements */
2764#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2765
2766static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2767 struct snd_ctl_elem_value *ucontrol)
2768{
2769 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002770 snd_hda_mixer_amp_switch_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002771}
2772
2773static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2774 struct snd_ctl_elem_value *ucontrol)
2775{
2776 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002777 snd_hda_mixer_amp_switch_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002778}
2779
Takashi Iwaia23b6882009-03-23 15:21:36 +01002780#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002781 { \
2782 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2783 .name = "Capture Switch", \
2784 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2785 .count = num, \
2786 .info = alc_cap_sw_info, \
2787 .get = alc_cap_sw_get, \
2788 .put = alc_cap_sw_put, \
2789 }, \
2790 { \
2791 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2792 .name = "Capture Volume", \
2793 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2794 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2795 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2796 .count = num, \
2797 .info = alc_cap_vol_info, \
2798 .get = alc_cap_vol_get, \
2799 .put = alc_cap_vol_put, \
2800 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002801 }
2802
2803#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002804 { \
2805 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2806 /* .name = "Capture Source", */ \
2807 .name = "Input Source", \
2808 .count = num, \
2809 .info = alc_mux_enum_info, \
2810 .get = alc_mux_enum_get, \
2811 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002812 }
2813
2814#define DEFINE_CAPMIX(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002815static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002816 _DEFINE_CAPMIX(num), \
2817 _DEFINE_CAPSRC(num), \
2818 { } /* end */ \
2819}
2820
2821#define DEFINE_CAPMIX_NOSRC(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002822static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002823 _DEFINE_CAPMIX(num), \
2824 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002825}
2826
2827/* up to three ADCs */
2828DEFINE_CAPMIX(1);
2829DEFINE_CAPMIX(2);
2830DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002831DEFINE_CAPMIX_NOSRC(1);
2832DEFINE_CAPMIX_NOSRC(2);
2833DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002834
2835/*
2836 * ALC880 5-stack model
2837 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002838 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2839 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002840 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2841 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2842 */
2843
2844/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02002845static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002846 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002847 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 { } /* end */
2849};
2850
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002851/* channel source setting (6/8 channel selection for 5-stack) */
2852/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002853static const struct hda_verb alc880_fivestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002854 /* set line-in to input, mute it */
2855 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2856 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002857 { } /* end */
2858};
2859
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002860/* 8ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002861static const struct hda_verb alc880_fivestack_ch8_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002862 /* set line-in to output, unmute it */
2863 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2864 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2865 { } /* end */
2866};
2867
Takashi Iwaia9111322011-05-02 11:30:18 +02002868static const struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002869 { 6, alc880_fivestack_ch6_init },
2870 { 8, alc880_fivestack_ch8_init },
2871};
2872
2873
2874/*
2875 * ALC880 6-stack model
2876 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002877 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2878 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002879 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2880 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2881 */
2882
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002883static const hda_nid_t alc880_6st_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002884 /* front, rear, clfe, rear_surr */
2885 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002886};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002887
Takashi Iwaia9111322011-05-02 11:30:18 +02002888static const struct hda_input_mux alc880_6stack_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002889 .num_items = 4,
2890 .items = {
2891 { "Mic", 0x0 },
2892 { "Front Mic", 0x1 },
2893 { "Line", 0x2 },
2894 { "CD", 0x4 },
2895 },
2896};
2897
2898/* fixed 8-channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002899static const struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002900 { 8, NULL },
2901};
2902
Takashi Iwaia9111322011-05-02 11:30:18 +02002903static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002904 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002905 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002906 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002907 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002908 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2909 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002910 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2911 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002912 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002913 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002914 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2915 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2916 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2917 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2918 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2919 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2920 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2921 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002922 {
2923 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2924 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002925 .info = alc_ch_mode_info,
2926 .get = alc_ch_mode_get,
2927 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002928 },
2929 { } /* end */
2930};
2931
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002932
2933/*
2934 * ALC880 W810 model
2935 *
2936 * W810 has rear IO for:
2937 * Front (DAC 02)
2938 * Surround (DAC 03)
2939 * Center/LFE (DAC 04)
2940 * Digital out (06)
2941 *
2942 * The system also has a pair of internal speakers, and a headphone jack.
2943 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002944 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002945 * There is a variable resistor to control the speaker or headphone
2946 * volume. This is a hardware-only device without a software API.
2947 *
2948 * Plugging headphones in will disable the internal speakers. This is
2949 * implemented in hardware, not via the driver using jack sense. In
2950 * a similar fashion, plugging into the rear socket marked "front" will
2951 * disable both the speakers and headphones.
2952 *
2953 * For input, there's a microphone jack, and an "audio in" jack.
2954 * These may not do anything useful with this driver yet, because I
2955 * haven't setup any initialization verbs for these yet...
2956 */
2957
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002958static const hda_nid_t alc880_w810_dac_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002959 /* front, rear/surround, clfe */
2960 0x02, 0x03, 0x04
2961};
2962
2963/* fixed 6 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002964static const struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002965 { 6, NULL }
2966};
2967
2968/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaia9111322011-05-02 11:30:18 +02002969static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002970 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002971 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002972 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002973 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002974 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2975 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002976 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2977 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002978 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2979 { } /* end */
2980};
2981
2982
2983/*
2984 * Z710V model
2985 *
2986 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002987 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2988 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002989 */
2990
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002991static const hda_nid_t alc880_z71v_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002992 0x02
2993};
2994#define ALC880_Z71V_HP_DAC 0x03
2995
2996/* fixed 2 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002997static const struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002998 { 2, NULL }
2999};
3000
Takashi Iwaia9111322011-05-02 11:30:18 +02003001static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003002 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003003 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003004 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003005 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003006 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3007 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3008 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3009 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3010 { } /* end */
3011};
3012
3013
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003014/*
3015 * ALC880 F1734 model
3016 *
3017 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
3018 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
3019 */
3020
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003021static const hda_nid_t alc880_f1734_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003022 0x03
3023};
3024#define ALC880_F1734_HP_DAC 0x02
3025
Takashi Iwaia9111322011-05-02 11:30:18 +02003026static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003027 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003028 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01003029 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3030 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003031 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3032 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01003033 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3034 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003035 { } /* end */
3036};
3037
Takashi Iwaia9111322011-05-02 11:30:18 +02003038static const struct hda_input_mux alc880_f1734_capture_source = {
Takashi Iwai937b4162008-02-11 14:52:36 +01003039 .num_items = 2,
3040 .items = {
3041 { "Mic", 0x1 },
3042 { "CD", 0x4 },
3043 },
3044};
3045
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003046
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003047/*
3048 * ALC880 ASUS model
3049 *
3050 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3051 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3052 * Mic = 0x18, Line = 0x1a
3053 */
3054
3055#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
3056#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
3057
Takashi Iwaia9111322011-05-02 11:30:18 +02003058static const struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003059 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003060 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003061 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003062 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003063 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3064 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003065 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3066 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003067 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3068 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3069 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3070 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3071 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3072 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003073 {
3074 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3075 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003076 .info = alc_ch_mode_info,
3077 .get = alc_ch_mode_get,
3078 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02003079 },
3080 { } /* end */
3081};
3082
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003083/*
3084 * ALC880 ASUS W1V model
3085 *
3086 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3087 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3088 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
3089 */
3090
3091/* additional mixers to alc880_asus_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02003092static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003093 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
3094 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003095 { } /* end */
3096};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003097
Kailang Yangdf694da2005-12-05 19:42:22 +01003098/* TCL S700 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003099static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003100 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3101 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3102 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
3103 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
3104 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
3105 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
3106 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
3107 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3108 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003109 { } /* end */
3110};
3111
Kailang Yangccc656c2006-10-17 12:32:26 +02003112/* Uniwill */
Takashi Iwaia9111322011-05-02 11:30:18 +02003113static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003114 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3115 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3116 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3117 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003118 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3119 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3120 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3121 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3122 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3123 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3124 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3125 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3126 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3127 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3128 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3129 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003130 {
3131 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3132 .name = "Channel Mode",
3133 .info = alc_ch_mode_info,
3134 .get = alc_ch_mode_get,
3135 .put = alc_ch_mode_put,
3136 },
3137 { } /* end */
3138};
3139
Takashi Iwaia9111322011-05-02 11:30:18 +02003140static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003141 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3142 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3143 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3144 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
3145 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3146 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01003147 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3148 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01003149 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3150 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003151 { } /* end */
3152};
3153
Takashi Iwaia9111322011-05-02 11:30:18 +02003154static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003155 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3156 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3157 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3158 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003159 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3160 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3161 { } /* end */
3162};
3163
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01003165 * virtual master controls
3166 */
3167
3168/*
3169 * slave controls for virtual master
3170 */
Takashi Iwaiea734962011-01-17 11:29:34 +01003171static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003172 "Front Playback Volume",
3173 "Surround Playback Volume",
3174 "Center Playback Volume",
3175 "LFE Playback Volume",
3176 "Side Playback Volume",
3177 "Headphone Playback Volume",
3178 "Speaker Playback Volume",
3179 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003180 "Line-Out Playback Volume",
3181 NULL,
3182};
3183
Takashi Iwaiea734962011-01-17 11:29:34 +01003184static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003185 "Front Playback Switch",
3186 "Surround Playback Switch",
3187 "Center Playback Switch",
3188 "LFE Playback Switch",
3189 "Side Playback Switch",
3190 "Headphone Playback Switch",
3191 "Speaker Playback Switch",
3192 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01003193 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01003194 "Line-Out Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003195 NULL,
3196};
3197
3198/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003199 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 */
Takashi Iwai603c4012008-07-30 15:01:44 +02003201
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003202#define NID_MAPPING (-1)
3203
3204#define SUBDEV_SPEAKER_ (0 << 6)
3205#define SUBDEV_HP_ (1 << 6)
3206#define SUBDEV_LINE_ (2 << 6)
3207#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
3208#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
3209#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
3210
Takashi Iwai603c4012008-07-30 15:01:44 +02003211static void alc_free_kctls(struct hda_codec *codec);
3212
Takashi Iwai67d634c2009-11-16 15:35:59 +01003213#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003214/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02003215static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003216 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003217 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003218 { } /* end */
3219};
Takashi Iwai67d634c2009-11-16 15:35:59 +01003220#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003221
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222static int alc_build_controls(struct hda_codec *codec)
3223{
3224 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02003225 struct snd_kcontrol *kctl = NULL;
Takashi Iwaia9111322011-05-02 11:30:18 +02003226 const struct snd_kcontrol_new *knew;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003227 int i, j, err;
3228 unsigned int u;
3229 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
3231 for (i = 0; i < spec->num_mixers; i++) {
3232 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
3233 if (err < 0)
3234 return err;
3235 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003236 if (spec->cap_mixer) {
3237 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
3238 if (err < 0)
3239 return err;
3240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003242 err = snd_hda_create_spdif_out_ctls(codec,
3243 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 if (err < 0)
3245 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003246 if (!spec->no_analog) {
3247 err = snd_hda_create_spdif_share_sw(codec,
3248 &spec->multiout);
3249 if (err < 0)
3250 return err;
3251 spec->multiout.share_spdif = 1;
3252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 }
3254 if (spec->dig_in_nid) {
3255 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3256 if (err < 0)
3257 return err;
3258 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01003259
Takashi Iwai67d634c2009-11-16 15:35:59 +01003260#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003261 /* create beep controls if needed */
3262 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02003263 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003264 for (knew = alc_beep_mixer; knew->name; knew++) {
3265 struct snd_kcontrol *kctl;
3266 kctl = snd_ctl_new1(knew, codec);
3267 if (!kctl)
3268 return -ENOMEM;
3269 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003270 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003271 if (err < 0)
3272 return err;
3273 }
3274 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01003275#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003276
Takashi Iwai2134ea42008-01-10 16:53:55 +01003277 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003278 if (!spec->no_analog &&
3279 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003280 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01003281 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003282 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003283 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003284 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003285 if (err < 0)
3286 return err;
3287 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003288 if (!spec->no_analog &&
3289 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003290 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
3291 NULL, alc_slave_sws);
3292 if (err < 0)
3293 return err;
3294 }
3295
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003296 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003297 if (spec->capsrc_nids || spec->adc_nids) {
3298 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
3299 if (!kctl)
3300 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3301 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003302 const hda_nid_t *nids = spec->capsrc_nids;
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003303 if (!nids)
3304 nids = spec->adc_nids;
3305 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3306 if (err < 0)
3307 return err;
3308 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003309 }
3310 if (spec->cap_mixer) {
3311 const char *kname = kctl ? kctl->id.name : NULL;
3312 for (knew = spec->cap_mixer; knew->name; knew++) {
3313 if (kname && strcmp(knew->name, kname) == 0)
3314 continue;
3315 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3316 for (i = 0; kctl && i < kctl->count; i++) {
3317 err = snd_hda_add_nid(codec, kctl, i,
3318 spec->adc_nids[i]);
3319 if (err < 0)
3320 return err;
3321 }
3322 }
3323 }
3324
3325 /* other nid->control mapping */
3326 for (i = 0; i < spec->num_mixers; i++) {
3327 for (knew = spec->mixers[i]; knew->name; knew++) {
3328 if (knew->iface != NID_MAPPING)
3329 continue;
3330 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3331 if (kctl == NULL)
3332 continue;
3333 u = knew->subdevice;
3334 for (j = 0; j < 4; j++, u >>= 8) {
3335 nid = u & 0x3f;
3336 if (nid == 0)
3337 continue;
3338 switch (u & 0xc0) {
3339 case SUBDEV_SPEAKER_:
3340 nid = spec->autocfg.speaker_pins[nid];
3341 break;
3342 case SUBDEV_LINE_:
3343 nid = spec->autocfg.line_out_pins[nid];
3344 break;
3345 case SUBDEV_HP_:
3346 nid = spec->autocfg.hp_pins[nid];
3347 break;
3348 default:
3349 continue;
3350 }
3351 err = snd_hda_add_nid(codec, kctl, 0, nid);
3352 if (err < 0)
3353 return err;
3354 }
3355 u = knew->private_value;
3356 for (j = 0; j < 4; j++, u >>= 8) {
3357 nid = u & 0xff;
3358 if (nid == 0)
3359 continue;
3360 err = snd_hda_add_nid(codec, kctl, 0, nid);
3361 if (err < 0)
3362 return err;
3363 }
3364 }
3365 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003366
3367 alc_free_kctls(codec); /* no longer needed */
3368
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 return 0;
3370}
3371
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003372
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373/*
3374 * initialize the codec volumes, etc
3375 */
3376
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003377/*
3378 * generic initialization of ADC, input mixers and output mixers
3379 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003380static const struct hda_verb alc880_volume_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003381 /*
3382 * Unmute ADC0-2 and set the default input to mic-in
3383 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003384 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003385 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003386 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003387 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003388 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003389 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003391 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3392 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003393 * Note: PASD motherboards uses the Line In 2 as the input for front
3394 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003396 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003397 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3398 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3399 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3400 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3401 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3402 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3403 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003405 /*
3406 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003408 /* set vol=0 to output mixers */
3409 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3410 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3411 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3412 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3413 /* set up input amps for analog loopback */
3414 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003415 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3416 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003417 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3418 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003419 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3420 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003421 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3422 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
3424 { }
3425};
3426
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003427/*
3428 * 3-stack pin configuration:
3429 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3430 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003431static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003432 /*
3433 * preset connection lists of input pins
3434 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3435 */
3436 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3437 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3438 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3439
3440 /*
3441 * Set pin mode and muting
3442 */
3443 /* set front pin widgets 0x14 for output */
3444 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3445 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3446 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3447 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3448 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3449 /* Mic2 (as headphone out) for HP output */
3450 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3451 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3452 /* Line In pin widget for input */
3453 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3454 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3455 /* Line2 (as front mic) pin widget for input and vref at 80% */
3456 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3457 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3458 /* CD pin widget for input */
3459 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3460
3461 { }
3462};
3463
3464/*
3465 * 5-stack pin configuration:
3466 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3467 * line-in/side = 0x1a, f-mic = 0x1b
3468 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003469static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003470 /*
3471 * preset connection lists of input pins
3472 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3473 */
3474 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3475 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3476
3477 /*
3478 * Set pin mode and muting
3479 */
3480 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003481 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3482 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3483 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3484 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003485 /* unmute pins for output (no gain on this amp) */
3486 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3487 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3488 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3489 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3490
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003492 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003493 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3494 /* Mic2 (as headphone out) for HP output */
3495 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003496 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003497 /* Line In pin widget for input */
3498 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3499 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3500 /* Line2 (as front mic) pin widget for input and vref at 80% */
3501 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3502 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3503 /* CD pin widget for input */
3504 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
3506 { }
3507};
3508
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003509/*
3510 * W810 pin configuration:
3511 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3512 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003513static const struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 /* hphone/speaker input selector: front DAC */
3515 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3516
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003517 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3518 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3519 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3520 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3521 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3522 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3523
3524 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003525 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 { }
3528};
3529
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003530/*
3531 * Z71V pin configuration:
3532 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3533 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003534static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003535 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003536 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003537 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003539
Takashi Iwai16ded522005-06-10 19:58:24 +02003540 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003541 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003542 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003543 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003544
3545 { }
3546};
3547
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003548/*
3549 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003550 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3551 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003552 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003553static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003554 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3555
Takashi Iwai16ded522005-06-10 19:58:24 +02003556 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003557 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003558 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003559 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003560 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003561 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003562 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003563 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3564
Takashi Iwai16ded522005-06-10 19:58:24 +02003565 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003566 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003567 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003568 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003569 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003570 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003571 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003572 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003573 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003574
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003575 { }
3576};
Takashi Iwai16ded522005-06-10 19:58:24 +02003577
Kailang Yangccc656c2006-10-17 12:32:26 +02003578/*
3579 * Uniwill pin configuration:
3580 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3581 * line = 0x1a
3582 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003583static const struct hda_verb alc880_uniwill_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003584 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3585
3586 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3587 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3588 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3589 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3590 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3591 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3592 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3593 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3594 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3595 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3596 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3597 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3598 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3599 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3600
3601 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3602 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3603 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3604 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3605 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3606 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3607 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3608 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3609 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3610
3611 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3612 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3613
3614 { }
3615};
3616
3617/*
3618* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003619* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003620 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003621static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003622 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3623
3624 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3625 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3626 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3627 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3628 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3629 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3630 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3631 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3632 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3633 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3634 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3635 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3636
3637 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3638 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3639 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3640 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3641 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3642 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3643
3644 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3645 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3646
3647 { }
3648};
3649
Takashi Iwaia9111322011-05-02 11:30:18 +02003650static const struct hda_verb alc880_beep_init_verbs[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003651 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3652 { }
3653};
3654
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003655/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003656static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003657{
3658 unsigned int present;
3659 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003660
Wu Fengguang864f92b2009-11-18 12:38:02 +08003661 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003662 bits = present ? HDA_AMP_MUTE : 0;
3663 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003664}
3665
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003666static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003667{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003668 struct alc_spec *spec = codec->spec;
3669
3670 spec->autocfg.hp_pins[0] = 0x14;
3671 spec->autocfg.speaker_pins[0] = 0x15;
3672 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02003673 spec->automute = 1;
3674 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003675}
3676
3677static void alc880_uniwill_init_hook(struct hda_codec *codec)
3678{
Takashi Iwaid922b512011-04-28 12:18:53 +02003679 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003680 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003681}
3682
3683static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3684 unsigned int res)
3685{
3686 /* Looks like the unsol event is incompatible with the standard
3687 * definition. 4bit tag is placed at 28 bit!
3688 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003689 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003690 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003691 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003692 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003693 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02003694 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003695 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003696 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003697}
3698
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003699static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003700{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003701 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003702
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003703 spec->autocfg.hp_pins[0] = 0x14;
3704 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02003705 spec->automute = 1;
3706 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangccc656c2006-10-17 12:32:26 +02003707}
3708
3709static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3710{
3711 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003712
Kailang Yangccc656c2006-10-17 12:32:26 +02003713 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003714 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3715 present &= HDA_AMP_VOLMASK;
3716 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3717 HDA_AMP_VOLMASK, present);
3718 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3719 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003720}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003721
Kailang Yangccc656c2006-10-17 12:32:26 +02003722static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3723 unsigned int res)
3724{
3725 /* Looks like the unsol event is incompatible with the standard
3726 * definition. 4bit tag is placed at 28 bit!
3727 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003728 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003729 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003730 else
Takashi Iwaid922b512011-04-28 12:18:53 +02003731 alc_sku_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003732}
3733
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003734/*
3735 * F1734 pin configuration:
3736 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3737 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003738static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003739 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003740 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3741 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3742 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3743 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3744
3745 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3746 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3747 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3748 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3749
3750 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3751 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003752 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003753 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3754 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3755 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3756 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3757 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3758 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003759
Takashi Iwai937b4162008-02-11 14:52:36 +01003760 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3761 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3762
Takashi Iwai16ded522005-06-10 19:58:24 +02003763 { }
3764};
3765
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003766/*
3767 * ASUS pin configuration:
3768 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3769 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003770static const struct hda_verb alc880_pin_asus_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003771 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3772 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3773 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3774 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3775
3776 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3777 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3778 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3779 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3780 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3781 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3782 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3783 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3784
3785 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3786 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3787 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3788 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3789 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3790 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3791 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3792 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3793 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003794
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003795 { }
3796};
3797
3798/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003799#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3800#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003801#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003802
Kailang Yangdf694da2005-12-05 19:42:22 +01003803/* Clevo m520g init */
Takashi Iwaia9111322011-05-02 11:30:18 +02003804static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003805 /* headphone output */
3806 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3807 /* line-out */
3808 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3809 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3810 /* Line-in */
3811 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3812 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3813 /* CD */
3814 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3815 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3816 /* Mic1 (rear panel) */
3817 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3818 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3819 /* Mic2 (front panel) */
3820 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3821 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3822 /* headphone */
3823 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3824 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3825 /* change to EAPD mode */
3826 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3827 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3828
3829 { }
3830};
3831
Takashi Iwaia9111322011-05-02 11:30:18 +02003832static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003833 /* change to EAPD mode */
3834 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3835 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3836
Kailang Yangdf694da2005-12-05 19:42:22 +01003837 /* Headphone output */
3838 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3839 /* Front output*/
3840 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3841 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3842
3843 /* Line In pin widget for input */
3844 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3845 /* CD pin widget for input */
3846 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3847 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3848 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3849
3850 /* change to EAPD mode */
3851 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3852 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3853
3854 { }
3855};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003856
3857/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003858 * LG m1 express dual
3859 *
3860 * Pin assignment:
3861 * Rear Line-In/Out (blue): 0x14
3862 * Build-in Mic-In: 0x15
3863 * Speaker-out: 0x17
3864 * HP-Out (green): 0x1b
3865 * Mic-In/Out (red): 0x19
3866 * SPDIF-Out: 0x1e
3867 */
3868
3869/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003870static const hda_nid_t alc880_lg_dac_nids[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003871 0x05, 0x02, 0x03
3872};
3873
3874/* seems analog CD is not working */
Takashi Iwaia9111322011-05-02 11:30:18 +02003875static const struct hda_input_mux alc880_lg_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003876 .num_items = 3,
3877 .items = {
3878 { "Mic", 0x1 },
3879 { "Line", 0x5 },
3880 { "Internal Mic", 0x6 },
3881 },
3882};
3883
3884/* 2,4,6 channel modes */
Takashi Iwaia9111322011-05-02 11:30:18 +02003885static const struct hda_verb alc880_lg_ch2_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003886 /* set line-in and mic-in to input */
3887 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3888 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3889 { }
3890};
3891
Takashi Iwaia9111322011-05-02 11:30:18 +02003892static const struct hda_verb alc880_lg_ch4_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003893 /* set line-in to out and mic-in to input */
3894 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3895 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3896 { }
3897};
3898
Takashi Iwaia9111322011-05-02 11:30:18 +02003899static const struct hda_verb alc880_lg_ch6_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003900 /* set line-in and mic-in to output */
3901 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3902 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3903 { }
3904};
3905
Takashi Iwaia9111322011-05-02 11:30:18 +02003906static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003907 { 2, alc880_lg_ch2_init },
3908 { 4, alc880_lg_ch4_init },
3909 { 6, alc880_lg_ch6_init },
3910};
3911
Takashi Iwaia9111322011-05-02 11:30:18 +02003912static const struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003913 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3914 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003915 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3916 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3917 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3918 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3919 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3920 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3921 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3922 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3923 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3924 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3925 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3926 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3927 {
3928 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3929 .name = "Channel Mode",
3930 .info = alc_ch_mode_info,
3931 .get = alc_ch_mode_get,
3932 .put = alc_ch_mode_put,
3933 },
3934 { } /* end */
3935};
3936
Takashi Iwaia9111322011-05-02 11:30:18 +02003937static const struct hda_verb alc880_lg_init_verbs[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003938 /* set capture source to mic-in */
3939 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3940 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3941 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3942 /* mute all amp mixer inputs */
3943 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003944 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3945 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003946 /* line-in to input */
3947 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3948 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3949 /* built-in mic */
3950 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3951 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3952 /* speaker-out */
3953 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3954 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3955 /* mic-in to input */
3956 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3957 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3958 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3959 /* HP-out */
3960 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3961 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3962 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3963 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003964 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003965 { }
3966};
3967
3968/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003969static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003970{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003971 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003972
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003973 spec->autocfg.hp_pins[0] = 0x1b;
3974 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02003975 spec->automute = 1;
3976 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003977}
3978
3979/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003980 * LG LW20
3981 *
3982 * Pin assignment:
3983 * Speaker-out: 0x14
3984 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003985 * Built-in Mic-In: 0x19
3986 * Line-In: 0x1b
3987 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003988 * SPDIF-Out: 0x1e
3989 */
3990
Takashi Iwaia9111322011-05-02 11:30:18 +02003991static const struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003992 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003993 .items = {
3994 { "Mic", 0x0 },
3995 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003996 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003997 },
3998};
3999
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004000#define alc880_lg_lw_modes alc880_threestack_modes
4001
Takashi Iwaia9111322011-05-02 11:30:18 +02004002static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004003 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4004 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4005 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
4006 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
4007 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
4008 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
4009 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
4010 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
4011 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4012 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01004013 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4014 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4015 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
4016 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004017 {
4018 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4019 .name = "Channel Mode",
4020 .info = alc_ch_mode_info,
4021 .get = alc_ch_mode_get,
4022 .put = alc_ch_mode_put,
4023 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004024 { } /* end */
4025};
4026
Takashi Iwaia9111322011-05-02 11:30:18 +02004027static const struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004028 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4029 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
4030 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
4031
Takashi Iwaid6815182006-03-23 16:06:23 +01004032 /* set capture source to mic-in */
4033 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4034 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4035 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02004036 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01004037 /* speaker-out */
4038 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4039 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4040 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01004041 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4042 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4043 /* mic-in to input */
4044 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4045 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4046 /* built-in mic */
4047 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4048 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4049 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004050 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01004051 { }
4052};
4053
4054/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004055static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01004056{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004057 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01004058
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004059 spec->autocfg.hp_pins[0] = 0x1b;
4060 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02004061 spec->automute = 1;
4062 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaid6815182006-03-23 16:06:23 +01004063}
4064
Takashi Iwaia9111322011-05-02 11:30:18 +02004065static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004066 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4067 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
4068 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4069 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4070 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
4071 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
4072 { } /* end */
4073};
4074
Takashi Iwaia9111322011-05-02 11:30:18 +02004075static const struct hda_input_mux alc880_medion_rim_capture_source = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004076 .num_items = 2,
4077 .items = {
4078 { "Mic", 0x0 },
4079 { "Internal Mic", 0x1 },
4080 },
4081};
4082
Takashi Iwaia9111322011-05-02 11:30:18 +02004083static const struct hda_verb alc880_medion_rim_init_verbs[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004084 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4085
4086 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4087 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4088
4089 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4090 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4091 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4092 /* Mic2 (as headphone out) for HP output */
4093 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4094 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4095 /* Internal Speaker */
4096 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4097 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4098
4099 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
4100 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
4101
4102 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4103 { }
4104};
4105
4106/* toggle speaker-output according to the hp-jack state */
4107static void alc880_medion_rim_automute(struct hda_codec *codec)
4108{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004109 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02004110 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004111 /* toggle EAPD */
4112 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004113 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
4114 else
4115 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
4116}
4117
4118static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
4119 unsigned int res)
4120{
4121 /* Looks like the unsol event is incompatible with the standard
4122 * definition. 4bit tag is placed at 28 bit!
4123 */
4124 if ((res >> 28) == ALC880_HP_EVENT)
4125 alc880_medion_rim_automute(codec);
4126}
4127
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004128static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004129{
4130 struct alc_spec *spec = codec->spec;
4131
4132 spec->autocfg.hp_pins[0] = 0x14;
4133 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02004134 spec->automute = 1;
4135 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004136}
4137
Takashi Iwaicb53c622007-08-10 17:21:45 +02004138#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02004139static const struct hda_amp_list alc880_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004140 { 0x0b, HDA_INPUT, 0 },
4141 { 0x0b, HDA_INPUT, 1 },
4142 { 0x0b, HDA_INPUT, 2 },
4143 { 0x0b, HDA_INPUT, 3 },
4144 { 0x0b, HDA_INPUT, 4 },
4145 { } /* end */
4146};
4147
Takashi Iwaia9111322011-05-02 11:30:18 +02004148static const struct hda_amp_list alc880_lg_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004149 { 0x0b, HDA_INPUT, 1 },
4150 { 0x0b, HDA_INPUT, 6 },
4151 { 0x0b, HDA_INPUT, 7 },
4152 { } /* end */
4153};
4154#endif
4155
Takashi Iwaid6815182006-03-23 16:06:23 +01004156/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004157 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004158 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004159
Takashi Iwai584c0c42011-03-10 12:51:11 +01004160static void alc_init_special_input_src(struct hda_codec *codec);
4161
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162static int alc_init(struct hda_codec *codec)
4163{
4164 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004165 unsigned int i;
4166
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004167 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004168 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004169
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004170 for (i = 0; i < spec->num_init_verbs; i++)
4171 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai584c0c42011-03-10 12:51:11 +01004172 alc_init_special_input_src(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004173
4174 if (spec->init_hook)
4175 spec->init_hook(codec);
4176
Takashi Iwai58701122011-01-13 15:41:45 +01004177 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
4178
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004179 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 return 0;
4181}
4182
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004183static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
4184{
4185 struct alc_spec *spec = codec->spec;
4186
4187 if (spec->unsol_event)
4188 spec->unsol_event(codec, res);
4189}
4190
Takashi Iwaicb53c622007-08-10 17:21:45 +02004191#ifdef CONFIG_SND_HDA_POWER_SAVE
4192static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
4193{
4194 struct alc_spec *spec = codec->spec;
4195 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
4196}
4197#endif
4198
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199/*
4200 * Analog playback callbacks
4201 */
4202static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
4203 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004204 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205{
4206 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01004207 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
4208 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209}
4210
4211static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4212 struct hda_codec *codec,
4213 unsigned int stream_tag,
4214 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004215 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216{
4217 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004218 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
4219 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220}
4221
4222static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4223 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004224 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225{
4226 struct alc_spec *spec = codec->spec;
4227 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
4228}
4229
4230/*
4231 * Digital out
4232 */
4233static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
4234 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004235 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236{
4237 struct alc_spec *spec = codec->spec;
4238 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
4239}
4240
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004241static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
4242 struct hda_codec *codec,
4243 unsigned int stream_tag,
4244 unsigned int format,
4245 struct snd_pcm_substream *substream)
4246{
4247 struct alc_spec *spec = codec->spec;
4248 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
4249 stream_tag, format, substream);
4250}
4251
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004252static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
4253 struct hda_codec *codec,
4254 struct snd_pcm_substream *substream)
4255{
4256 struct alc_spec *spec = codec->spec;
4257 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
4258}
4259
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
4261 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004262 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263{
4264 struct alc_spec *spec = codec->spec;
4265 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4266}
4267
4268/*
4269 * Analog capture
4270 */
Takashi Iwai63300792008-01-24 15:31:36 +01004271static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 struct hda_codec *codec,
4273 unsigned int stream_tag,
4274 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004275 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276{
4277 struct alc_spec *spec = codec->spec;
4278
Takashi Iwai63300792008-01-24 15:31:36 +01004279 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 stream_tag, 0, format);
4281 return 0;
4282}
4283
Takashi Iwai63300792008-01-24 15:31:36 +01004284static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004286 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287{
4288 struct alc_spec *spec = codec->spec;
4289
Takashi Iwai888afa12008-03-18 09:57:50 +01004290 snd_hda_codec_cleanup_stream(codec,
4291 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 return 0;
4293}
4294
Takashi Iwai840b64c2010-07-13 22:49:01 +02004295/* analog capture with dynamic dual-adc changes */
4296static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
4297 struct hda_codec *codec,
4298 unsigned int stream_tag,
4299 unsigned int format,
4300 struct snd_pcm_substream *substream)
4301{
4302 struct alc_spec *spec = codec->spec;
4303 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
4304 spec->cur_adc_stream_tag = stream_tag;
4305 spec->cur_adc_format = format;
4306 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
4307 return 0;
4308}
4309
4310static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
4311 struct hda_codec *codec,
4312 struct snd_pcm_substream *substream)
4313{
4314 struct alc_spec *spec = codec->spec;
4315 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4316 spec->cur_adc = 0;
4317 return 0;
4318}
4319
Takashi Iwaia9111322011-05-02 11:30:18 +02004320static const struct hda_pcm_stream dualmic_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02004321 .substreams = 1,
4322 .channels_min = 2,
4323 .channels_max = 2,
4324 .nid = 0, /* fill later */
4325 .ops = {
4326 .prepare = dualmic_capture_pcm_prepare,
4327 .cleanup = dualmic_capture_pcm_cleanup
4328 },
4329};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330
4331/*
4332 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004333static const struct hda_pcm_stream alc880_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 .substreams = 1,
4335 .channels_min = 2,
4336 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004337 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 .ops = {
4339 .open = alc880_playback_pcm_open,
4340 .prepare = alc880_playback_pcm_prepare,
4341 .cleanup = alc880_playback_pcm_cleanup
4342 },
4343};
4344
Takashi Iwaia9111322011-05-02 11:30:18 +02004345static const struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004346 .substreams = 1,
4347 .channels_min = 2,
4348 .channels_max = 2,
4349 /* NID is set in alc_build_pcms */
4350};
4351
Takashi Iwaia9111322011-05-02 11:30:18 +02004352static const struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01004353 .substreams = 1,
4354 .channels_min = 2,
4355 .channels_max = 2,
4356 /* NID is set in alc_build_pcms */
4357};
4358
Takashi Iwaia9111322011-05-02 11:30:18 +02004359static const struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004360 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 .channels_min = 2,
4362 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004363 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01004365 .prepare = alc880_alt_capture_pcm_prepare,
4366 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 },
4368};
4369
Takashi Iwaia9111322011-05-02 11:30:18 +02004370static const struct hda_pcm_stream alc880_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 .substreams = 1,
4372 .channels_min = 2,
4373 .channels_max = 2,
4374 /* NID is set in alc_build_pcms */
4375 .ops = {
4376 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004377 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004378 .prepare = alc880_dig_playback_pcm_prepare,
4379 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 },
4381};
4382
Takashi Iwaia9111322011-05-02 11:30:18 +02004383static const struct hda_pcm_stream alc880_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 .substreams = 1,
4385 .channels_min = 2,
4386 .channels_max = 2,
4387 /* NID is set in alc_build_pcms */
4388};
4389
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004390/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02004391static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004392 .substreams = 0,
4393 .channels_min = 0,
4394 .channels_max = 0,
4395};
4396
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397static int alc_build_pcms(struct hda_codec *codec)
4398{
4399 struct alc_spec *spec = codec->spec;
4400 struct hda_pcm *info = spec->pcm_rec;
4401 int i;
4402
4403 codec->num_pcms = 1;
4404 codec->pcm_info = info;
4405
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004406 if (spec->no_analog)
4407 goto skip_analog;
4408
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004409 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4410 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004412
Takashi Iwai4a471b72005-12-07 13:56:29 +01004413 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004414 if (snd_BUG_ON(!spec->multiout.dac_nids))
4415 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004416 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
4417 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4418 }
4419 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004420 if (snd_BUG_ON(!spec->adc_nids))
4421 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004422 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
4423 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
Takashi Iwai4a471b72005-12-07 13:56:29 +01004426 if (spec->channel_mode) {
4427 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4428 for (i = 0; i < spec->num_channel_mode; i++) {
4429 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4430 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 }
4433 }
4434
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004435 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004436 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004438 snprintf(spec->stream_name_digital,
4439 sizeof(spec->stream_name_digital),
4440 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004441 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004442 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004443 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004445 if (spec->dig_out_type)
4446 info->pcm_type = spec->dig_out_type;
4447 else
4448 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004449 if (spec->multiout.dig_out_nid &&
4450 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4452 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4453 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004454 if (spec->dig_in_nid &&
4455 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4457 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4458 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004459 /* FIXME: do we need this for all Realtek codec models? */
4460 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 }
4462
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004463 if (spec->no_analog)
4464 return 0;
4465
Takashi Iwaie08a0072006-09-07 17:52:14 +02004466 /* If the use of more than one ADC is requested for the current
4467 * model, configure a second analog capture-only PCM.
4468 */
4469 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004470 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4471 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004472 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004473 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004474 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004475 if (spec->alt_dac_nid) {
4476 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4477 *spec->stream_analog_alt_playback;
4478 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4479 spec->alt_dac_nid;
4480 } else {
4481 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4482 alc_pcm_null_stream;
4483 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4484 }
Raymond Yauce85c9a2011-05-03 13:33:53 +08004485 if (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture) {
Takashi Iwai63300792008-01-24 15:31:36 +01004486 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4487 *spec->stream_analog_alt_capture;
4488 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4489 spec->adc_nids[1];
4490 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4491 spec->num_adc_nids - 1;
4492 } else {
4493 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4494 alc_pcm_null_stream;
4495 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004496 }
4497 }
4498
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 return 0;
4500}
4501
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004502static inline void alc_shutup(struct hda_codec *codec)
4503{
Takashi Iwai1c716152011-04-07 10:37:16 +02004504 struct alc_spec *spec = codec->spec;
4505
4506 if (spec && spec->shutup)
4507 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004508 snd_hda_shutup_pins(codec);
4509}
4510
Takashi Iwai603c4012008-07-30 15:01:44 +02004511static void alc_free_kctls(struct hda_codec *codec)
4512{
4513 struct alc_spec *spec = codec->spec;
4514
4515 if (spec->kctls.list) {
4516 struct snd_kcontrol_new *kctl = spec->kctls.list;
4517 int i;
4518 for (i = 0; i < spec->kctls.used; i++)
4519 kfree(kctl[i].name);
4520 }
4521 snd_array_free(&spec->kctls);
4522}
4523
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524static void alc_free(struct hda_codec *codec)
4525{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004526 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004527
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004528 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004529 return;
4530
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004531 alc_shutup(codec);
Takashi Iwaicd372fb2011-03-03 14:40:14 +01004532 snd_hda_input_jack_free(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004533 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004534 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004535 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536}
4537
Hector Martinf5de24b2009-12-20 22:51:31 +01004538#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004539static void alc_power_eapd(struct hda_codec *codec)
4540{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02004541 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004542}
4543
Hector Martinf5de24b2009-12-20 22:51:31 +01004544static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4545{
4546 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004547 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004548 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004549 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004550 return 0;
4551}
4552#endif
4553
Takashi Iwaie044c392008-10-27 16:56:24 +01004554#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004555static int alc_resume(struct hda_codec *codec)
4556{
Takashi Iwai1c716152011-04-07 10:37:16 +02004557 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01004558 codec->patch_ops.init(codec);
4559 snd_hda_codec_resume_amp(codec);
4560 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004561 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004562 return 0;
4563}
Takashi Iwaie044c392008-10-27 16:56:24 +01004564#endif
4565
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566/*
4567 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004568static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 .build_controls = alc_build_controls,
4570 .build_pcms = alc_build_pcms,
4571 .init = alc_init,
4572 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004573 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004574#ifdef SND_HDA_NEEDS_RESUME
4575 .resume = alc_resume,
4576#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004577#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004578 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004579 .check_power_status = alc_check_power_status,
4580#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004581 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582};
4583
Kailang Yangc027ddc2010-03-19 11:33:06 +01004584/* replace the codec chip_name with the given string */
4585static int alc_codec_rename(struct hda_codec *codec, const char *name)
4586{
4587 kfree(codec->chip_name);
4588 codec->chip_name = kstrdup(name, GFP_KERNEL);
4589 if (!codec->chip_name) {
4590 alc_free(codec);
4591 return -ENOMEM;
4592 }
4593 return 0;
4594}
4595
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004596/*
4597 * Test configuration for debugging
4598 *
4599 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4600 * enum controls.
4601 */
4602#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004603static const hda_nid_t alc880_test_dac_nids[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004604 0x02, 0x03, 0x04, 0x05
4605};
4606
Takashi Iwaia9111322011-05-02 11:30:18 +02004607static const struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004608 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004609 .items = {
4610 { "In-1", 0x0 },
4611 { "In-2", 0x1 },
4612 { "In-3", 0x2 },
4613 { "In-4", 0x3 },
4614 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004615 { "Front", 0x5 },
4616 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004617 },
4618};
4619
Takashi Iwaia9111322011-05-02 11:30:18 +02004620static const struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004621 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004622 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004623 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004624 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004625};
4626
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004627static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4628 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004629{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004630 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004631 "N/A", "Line Out", "HP Out",
4632 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4633 };
4634 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4635 uinfo->count = 1;
4636 uinfo->value.enumerated.items = 8;
4637 if (uinfo->value.enumerated.item >= 8)
4638 uinfo->value.enumerated.item = 7;
4639 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4640 return 0;
4641}
4642
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004643static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4644 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004645{
4646 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4647 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4648 unsigned int pin_ctl, item = 0;
4649
4650 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4651 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4652 if (pin_ctl & AC_PINCTL_OUT_EN) {
4653 if (pin_ctl & AC_PINCTL_HP_EN)
4654 item = 2;
4655 else
4656 item = 1;
4657 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4658 switch (pin_ctl & AC_PINCTL_VREFEN) {
4659 case AC_PINCTL_VREF_HIZ: item = 3; break;
4660 case AC_PINCTL_VREF_50: item = 4; break;
4661 case AC_PINCTL_VREF_GRD: item = 5; break;
4662 case AC_PINCTL_VREF_80: item = 6; break;
4663 case AC_PINCTL_VREF_100: item = 7; break;
4664 }
4665 }
4666 ucontrol->value.enumerated.item[0] = item;
4667 return 0;
4668}
4669
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004670static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4671 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004672{
4673 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4674 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004675 static const unsigned int ctls[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004676 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4677 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4678 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4679 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4680 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4681 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4682 };
4683 unsigned int old_ctl, new_ctl;
4684
4685 old_ctl = snd_hda_codec_read(codec, nid, 0,
4686 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4687 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4688 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004689 int val;
4690 snd_hda_codec_write_cache(codec, nid, 0,
4691 AC_VERB_SET_PIN_WIDGET_CONTROL,
4692 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004693 val = ucontrol->value.enumerated.item[0] >= 3 ?
4694 HDA_AMP_MUTE : 0;
4695 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4696 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004697 return 1;
4698 }
4699 return 0;
4700}
4701
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004702static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4703 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004704{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004705 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004706 "Front", "Surround", "CLFE", "Side"
4707 };
4708 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4709 uinfo->count = 1;
4710 uinfo->value.enumerated.items = 4;
4711 if (uinfo->value.enumerated.item >= 4)
4712 uinfo->value.enumerated.item = 3;
4713 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4714 return 0;
4715}
4716
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004717static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4718 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004719{
4720 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4721 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4722 unsigned int sel;
4723
4724 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4725 ucontrol->value.enumerated.item[0] = sel & 3;
4726 return 0;
4727}
4728
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004729static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4730 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004731{
4732 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4733 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4734 unsigned int sel;
4735
4736 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4737 if (ucontrol->value.enumerated.item[0] != sel) {
4738 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004739 snd_hda_codec_write_cache(codec, nid, 0,
4740 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004741 return 1;
4742 }
4743 return 0;
4744}
4745
4746#define PIN_CTL_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_ctl_info, \
4751 .get = alc_test_pin_ctl_get, \
4752 .put = alc_test_pin_ctl_put, \
4753 .private_value = nid \
4754 }
4755
4756#define PIN_SRC_TEST(xname,nid) { \
4757 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4758 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004759 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004760 .info = alc_test_pin_src_info, \
4761 .get = alc_test_pin_src_get, \
4762 .put = alc_test_pin_src_put, \
4763 .private_value = nid \
4764 }
4765
Takashi Iwaia9111322011-05-02 11:30:18 +02004766static const struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004767 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4768 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4769 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4770 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004771 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4772 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4773 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4774 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004775 PIN_CTL_TEST("Front Pin Mode", 0x14),
4776 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4777 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4778 PIN_CTL_TEST("Side Pin Mode", 0x17),
4779 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4780 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4781 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4782 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4783 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4784 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4785 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4786 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4787 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4788 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4789 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4790 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4791 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4792 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4793 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4794 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4795 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4796 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004797 {
4798 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4799 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004800 .info = alc_ch_mode_info,
4801 .get = alc_ch_mode_get,
4802 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004803 },
4804 { } /* end */
4805};
4806
Takashi Iwaia9111322011-05-02 11:30:18 +02004807static const struct hda_verb alc880_test_init_verbs[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004808 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004809 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4810 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4811 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4812 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4813 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4814 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4815 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4816 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004817 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004818 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4819 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4820 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4821 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004822 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004823 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4824 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4825 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4826 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004827 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004828 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4829 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4830 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4831 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004832 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004833 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4834 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004835 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4836 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4837 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004838 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004839 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4840 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4841 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4842 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004843 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004844 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004845 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004846 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004847 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004848 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004849 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004850 /* Analog input/passthru */
4851 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4852 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4853 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4854 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4855 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004856 { }
4857};
4858#endif
4859
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860/*
4861 */
4862
Takashi Iwaiea734962011-01-17 11:29:34 +01004863static const char * const alc880_models[ALC880_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004864 [ALC880_3ST] = "3stack",
4865 [ALC880_TCL_S700] = "tcl",
4866 [ALC880_3ST_DIG] = "3stack-digout",
4867 [ALC880_CLEVO] = "clevo",
4868 [ALC880_5ST] = "5stack",
4869 [ALC880_5ST_DIG] = "5stack-digout",
4870 [ALC880_W810] = "w810",
4871 [ALC880_Z71V] = "z71v",
4872 [ALC880_6ST] = "6stack",
4873 [ALC880_6ST_DIG] = "6stack-digout",
4874 [ALC880_ASUS] = "asus",
4875 [ALC880_ASUS_W1V] = "asus-w1v",
4876 [ALC880_ASUS_DIG] = "asus-dig",
4877 [ALC880_ASUS_DIG2] = "asus-dig2",
4878 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004879 [ALC880_UNIWILL_P53] = "uniwill-p53",
4880 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004881 [ALC880_F1734] = "F1734",
4882 [ALC880_LG] = "lg",
4883 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004884 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004885#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004886 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004887#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004888 [ALC880_AUTO] = "auto",
4889};
4890
Takashi Iwaia9111322011-05-02 11:30:18 +02004891static const struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004892 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004893 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4894 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4895 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4896 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4897 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4898 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4899 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4900 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004901 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004902 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4903 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4904 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4905 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4906 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4907 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4908 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4909 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4910 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4911 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004912 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004913 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4914 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4915 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004916 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004917 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004918 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4919 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004920 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4921 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004922 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4923 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4924 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4925 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004926 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4927 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004928 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004929 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004930 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Justin P. Mattocka2e2bc22011-02-24 22:16:02 -08004931 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004932 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4933 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004934 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004935 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004936 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004937 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004938 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004939 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004940 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004941 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004942 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004943 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05004944 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004945 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004946 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004947 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4948 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4949 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4950 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004951 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4952 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004953 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004954 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004955 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4956 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004957 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4958 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4959 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004960 /* default Intel */
4961 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004962 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4963 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 {}
4965};
4966
Takashi Iwai16ded522005-06-10 19:58:24 +02004967/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004968 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004969 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004970static const struct alc_config_preset alc880_presets[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02004971 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004972 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004973 .init_verbs = { alc880_volume_init_verbs,
4974 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004975 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004976 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004977 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4978 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004979 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004980 .input_mux = &alc880_capture_source,
4981 },
4982 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004983 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004984 .init_verbs = { alc880_volume_init_verbs,
4985 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004986 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004987 .dac_nids = alc880_dac_nids,
4988 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004989 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4990 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004991 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004992 .input_mux = &alc880_capture_source,
4993 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004994 [ALC880_TCL_S700] = {
4995 .mixers = { alc880_tcl_s700_mixer },
4996 .init_verbs = { alc880_volume_init_verbs,
4997 alc880_pin_tcl_S700_init_verbs,
4998 alc880_gpio2_init_verbs },
4999 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5000 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005001 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
5002 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01005003 .hp_nid = 0x03,
5004 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5005 .channel_mode = alc880_2_jack_modes,
5006 .input_mux = &alc880_capture_source,
5007 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005008 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005009 .mixers = { alc880_three_stack_mixer,
5010 alc880_five_stack_mixer},
5011 .init_verbs = { alc880_volume_init_verbs,
5012 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005013 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5014 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005015 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5016 .channel_mode = alc880_fivestack_modes,
5017 .input_mux = &alc880_capture_source,
5018 },
5019 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005020 .mixers = { alc880_three_stack_mixer,
5021 alc880_five_stack_mixer },
5022 .init_verbs = { alc880_volume_init_verbs,
5023 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005024 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5025 .dac_nids = alc880_dac_nids,
5026 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005027 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5028 .channel_mode = alc880_fivestack_modes,
5029 .input_mux = &alc880_capture_source,
5030 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005031 [ALC880_6ST] = {
5032 .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 Iwaib6482d42005-06-27 15:32:43 +02005035 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5036 .dac_nids = alc880_6st_dac_nids,
5037 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5038 .channel_mode = alc880_sixstack_modes,
5039 .input_mux = &alc880_6stack_capture_source,
5040 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005041 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005042 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005043 .init_verbs = { alc880_volume_init_verbs,
5044 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005045 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5046 .dac_nids = alc880_6st_dac_nids,
5047 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005048 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5049 .channel_mode = alc880_sixstack_modes,
5050 .input_mux = &alc880_6stack_capture_source,
5051 },
5052 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005053 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005054 .init_verbs = { alc880_volume_init_verbs,
5055 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005056 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005057 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
5058 .dac_nids = alc880_w810_dac_nids,
5059 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005060 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
5061 .channel_mode = alc880_w810_modes,
5062 .input_mux = &alc880_capture_source,
5063 },
5064 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005065 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005066 .init_verbs = { alc880_volume_init_verbs,
5067 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005068 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
5069 .dac_nids = alc880_z71v_dac_nids,
5070 .dig_out_nid = ALC880_DIGOUT_NID,
5071 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005072 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5073 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02005074 .input_mux = &alc880_capture_source,
5075 },
5076 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005077 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005078 .init_verbs = { alc880_volume_init_verbs,
5079 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005080 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
5081 .dac_nids = alc880_f1734_dac_nids,
5082 .hp_nid = 0x02,
5083 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5084 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01005085 .input_mux = &alc880_f1734_capture_source,
5086 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005087 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005088 .init_hook = alc_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02005089 },
5090 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005091 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005092 .init_verbs = { alc880_volume_init_verbs,
5093 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005094 alc880_gpio1_init_verbs },
5095 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5096 .dac_nids = alc880_asus_dac_nids,
5097 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5098 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005099 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005100 .input_mux = &alc880_capture_source,
5101 },
5102 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005103 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005104 .init_verbs = { alc880_volume_init_verbs,
5105 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005106 alc880_gpio1_init_verbs },
5107 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5108 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005109 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005110 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5111 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005112 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005113 .input_mux = &alc880_capture_source,
5114 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005115 [ALC880_ASUS_DIG2] = {
5116 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005117 .init_verbs = { alc880_volume_init_verbs,
5118 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01005119 alc880_gpio2_init_verbs }, /* use GPIO2 */
5120 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5121 .dac_nids = alc880_asus_dac_nids,
5122 .dig_out_nid = ALC880_DIGOUT_NID,
5123 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5124 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005125 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005126 .input_mux = &alc880_capture_source,
5127 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005128 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005129 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005130 .init_verbs = { alc880_volume_init_verbs,
5131 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005132 alc880_gpio1_init_verbs },
5133 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5134 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005135 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005136 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5137 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005138 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005139 .input_mux = &alc880_capture_source,
5140 },
5141 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005142 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02005143 .init_verbs = { alc880_volume_init_verbs,
5144 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005145 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5146 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005147 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005148 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5149 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005150 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005151 .input_mux = &alc880_capture_source,
5152 },
Kailang Yangccc656c2006-10-17 12:32:26 +02005153 [ALC880_UNIWILL] = {
5154 .mixers = { alc880_uniwill_mixer },
5155 .init_verbs = { alc880_volume_init_verbs,
5156 alc880_uniwill_init_verbs },
5157 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5158 .dac_nids = alc880_asus_dac_nids,
5159 .dig_out_nid = ALC880_DIGOUT_NID,
5160 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5161 .channel_mode = alc880_threestack_modes,
5162 .need_dac_fix = 1,
5163 .input_mux = &alc880_capture_source,
5164 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005165 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02005166 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02005167 },
5168 [ALC880_UNIWILL_P53] = {
5169 .mixers = { alc880_uniwill_p53_mixer },
5170 .init_verbs = { alc880_volume_init_verbs,
5171 alc880_uniwill_p53_init_verbs },
5172 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5173 .dac_nids = alc880_asus_dac_nids,
5174 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005175 .channel_mode = alc880_threestack_modes,
5176 .input_mux = &alc880_capture_source,
5177 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005178 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005179 .init_hook = alc_hp_automute,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005180 },
5181 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005182 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005183 .init_verbs = { alc880_volume_init_verbs,
5184 alc880_uniwill_p53_init_verbs,
5185 alc880_beep_init_verbs },
5186 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5187 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02005188 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005189 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5190 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02005191 .input_mux = &alc880_capture_source,
5192 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005193 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005194 .init_hook = alc_hp_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02005195 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005196 [ALC880_CLEVO] = {
5197 .mixers = { alc880_three_stack_mixer },
5198 .init_verbs = { alc880_volume_init_verbs,
5199 alc880_pin_clevo_init_verbs },
5200 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5201 .dac_nids = alc880_dac_nids,
5202 .hp_nid = 0x03,
5203 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5204 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005205 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005206 .input_mux = &alc880_capture_source,
5207 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005208 [ALC880_LG] = {
5209 .mixers = { alc880_lg_mixer },
5210 .init_verbs = { alc880_volume_init_verbs,
5211 alc880_lg_init_verbs },
5212 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
5213 .dac_nids = alc880_lg_dac_nids,
5214 .dig_out_nid = ALC880_DIGOUT_NID,
5215 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
5216 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005217 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005218 .input_mux = &alc880_lg_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005219 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005220 .setup = alc880_lg_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005221 .init_hook = alc_hp_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005222#ifdef CONFIG_SND_HDA_POWER_SAVE
5223 .loopbacks = alc880_lg_loopbacks,
5224#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005225 },
Takashi Iwaid6815182006-03-23 16:06:23 +01005226 [ALC880_LG_LW] = {
5227 .mixers = { alc880_lg_lw_mixer },
5228 .init_verbs = { alc880_volume_init_verbs,
5229 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005230 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01005231 .dac_nids = alc880_dac_nids,
5232 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005233 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
5234 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01005235 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005236 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005237 .setup = alc880_lg_lw_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005238 .init_hook = alc_hp_automute,
Takashi Iwaid6815182006-03-23 16:06:23 +01005239 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005240 [ALC880_MEDION_RIM] = {
5241 .mixers = { alc880_medion_rim_mixer },
5242 .init_verbs = { alc880_volume_init_verbs,
5243 alc880_medion_rim_init_verbs,
5244 alc_gpio2_init_verbs },
5245 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5246 .dac_nids = alc880_dac_nids,
5247 .dig_out_nid = ALC880_DIGOUT_NID,
5248 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5249 .channel_mode = alc880_2_jack_modes,
5250 .input_mux = &alc880_medion_rim_capture_source,
5251 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005252 .setup = alc880_medion_rim_setup,
5253 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005254 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005255#ifdef CONFIG_SND_DEBUG
5256 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005257 .mixers = { alc880_test_mixer },
5258 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005259 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
5260 .dac_nids = alc880_test_dac_nids,
5261 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005262 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
5263 .channel_mode = alc880_test_modes,
5264 .input_mux = &alc880_test_capture_source,
5265 },
5266#endif
5267};
5268
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005269/*
5270 * Automatic parse of I/O pins from the BIOS configuration
5271 */
5272
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005273enum {
5274 ALC_CTL_WIDGET_VOL,
5275 ALC_CTL_WIDGET_MUTE,
5276 ALC_CTL_BIND_MUTE,
5277};
Takashi Iwaia9111322011-05-02 11:30:18 +02005278static const struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005279 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
5280 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01005281 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005282};
5283
Takashi Iwaice764ab2011-04-27 16:35:23 +02005284static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
5285{
5286 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
5287 return snd_array_new(&spec->kctls);
5288}
5289
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005290/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005291static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005292 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005293{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005294 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005295
Takashi Iwaice764ab2011-04-27 16:35:23 +02005296 knew = alc_kcontrol_new(spec);
Takashi Iwai603c4012008-07-30 15:01:44 +02005297 if (!knew)
5298 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005299 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07005300 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005301 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005302 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005303 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01005304 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01005305 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005306 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005307 return 0;
5308}
5309
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005310static int add_control_with_pfx(struct alc_spec *spec, int type,
5311 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005312 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005313{
5314 char name[32];
5315 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005316 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005317}
5318
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005319#define add_pb_vol_ctrl(spec, type, pfx, val) \
5320 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5321#define add_pb_sw_ctrl(spec, type, pfx, val) \
5322 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5323#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5324 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5325#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5326 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005327
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005328#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5329#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5330#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5331#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005332#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5333#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5334#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5335#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5336#define ALC880_PIN_CD_NID 0x1c
5337
5338/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005339static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
5340 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005341{
5342 hda_nid_t nid;
5343 int assigned[4];
5344 int i, j;
5345
5346 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005347 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005348
5349 /* check the pins hardwired to audio widget */
5350 for (i = 0; i < cfg->line_outs; i++) {
5351 nid = cfg->line_out_pins[i];
5352 if (alc880_is_fixed_pin(nid)) {
5353 int idx = alc880_fixed_pin_idx(nid);
Takashi Iwaidda14412011-05-02 11:29:30 +02005354 spec->private_dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005355 assigned[idx] = 1;
5356 }
5357 }
5358 /* left pins can be connect to any audio widget */
5359 for (i = 0; i < cfg->line_outs; i++) {
5360 nid = cfg->line_out_pins[i];
5361 if (alc880_is_fixed_pin(nid))
5362 continue;
5363 /* search for an empty channel */
5364 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005365 if (!assigned[j]) {
Takashi Iwaidda14412011-05-02 11:29:30 +02005366 spec->private_dac_nids[i] =
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005367 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005368 assigned[j] = 1;
5369 break;
5370 }
5371 }
5372 }
5373 spec->multiout.num_dacs = cfg->line_outs;
5374 return 0;
5375}
5376
Takashi Iwaice764ab2011-04-27 16:35:23 +02005377static const char *alc_get_line_out_pfx(struct alc_spec *spec,
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005378 bool can_be_master)
5379{
Takashi Iwaice764ab2011-04-27 16:35:23 +02005380 struct auto_pin_cfg *cfg = &spec->autocfg;
5381
5382 if (cfg->line_outs == 1 && !spec->multi_ios &&
5383 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005384 return "Master";
5385
5386 switch (cfg->line_out_type) {
5387 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01005388 if (cfg->line_outs == 1)
5389 return "Speaker";
5390 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005391 case AUTO_PIN_HP_OUT:
5392 return "Headphone";
5393 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02005394 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005395 return "PCM";
5396 break;
5397 }
5398 return NULL;
5399}
5400
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005401/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01005402static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
5403 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005404{
Takashi Iwaiea734962011-01-17 11:29:34 +01005405 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005406 "Front", "Surround", NULL /*CLFE*/, "Side"
5407 };
Takashi Iwaice764ab2011-04-27 16:35:23 +02005408 const char *pfx = alc_get_line_out_pfx(spec, false);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005409 hda_nid_t nid;
Takashi Iwaice764ab2011-04-27 16:35:23 +02005410 int i, err, noutputs;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005411
Takashi Iwaice764ab2011-04-27 16:35:23 +02005412 noutputs = cfg->line_outs;
5413 if (spec->multi_ios > 0)
5414 noutputs += spec->multi_ios;
5415
5416 for (i = 0; i < noutputs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005417 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005418 continue;
5419 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005420 if (!pfx && i == 2) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005421 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005422 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5423 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005424 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
5425 HDA_OUTPUT));
5426 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005427 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005428 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5429 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005430 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
5431 HDA_OUTPUT));
5432 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005433 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005434 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5435 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005436 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
5437 HDA_INPUT));
5438 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005439 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005440 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5441 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005442 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
5443 HDA_INPUT));
5444 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005445 return err;
5446 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005447 const char *name = pfx;
David Henningsson7e59e092011-03-04 14:22:25 +01005448 int index = i;
5449 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005450 name = chname[i];
David Henningsson7e59e092011-03-04 14:22:25 +01005451 index = 0;
5452 }
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005453 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
David Henningsson7e59e092011-03-04 14:22:25 +01005454 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005455 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
5456 HDA_OUTPUT));
5457 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005458 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005459 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
David Henningsson7e59e092011-03-04 14:22:25 +01005460 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005461 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
5462 HDA_INPUT));
5463 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005464 return err;
5465 }
5466 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005467 return 0;
5468}
5469
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005470/* add playback controls for speaker and HP outputs */
5471static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
5472 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005473{
5474 hda_nid_t nid;
5475 int err;
5476
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005477 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005478 return 0;
5479
5480 if (alc880_is_fixed_pin(pin)) {
5481 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01005482 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005483 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005484 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005485 else
5486 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005487 /* control HP volume/switch on the output mixer amp */
5488 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005489 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005490 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
5491 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005492 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005493 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005494 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
5495 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005496 return err;
5497 } else if (alc880_is_multi_pin(pin)) {
5498 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005499 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005500 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005501 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5502 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005503 return err;
5504 }
5505 return 0;
5506}
5507
5508/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005509static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005510 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005511 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005512{
Kailang Yangdf694da2005-12-05 19:42:22 +01005513 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005514
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005515 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005516 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5517 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005518 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005519 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005520 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5521 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005522 return err;
5523 return 0;
5524}
5525
Takashi Iwai05f5f472009-08-25 13:10:18 +02005526static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005527{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005528 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5529 return (pincap & AC_PINCAP_IN) != 0;
5530}
5531
5532/* create playback/capture controls for input pins */
5533static int alc_auto_create_input_ctls(struct hda_codec *codec,
5534 const struct auto_pin_cfg *cfg,
5535 hda_nid_t mixer,
5536 hda_nid_t cap1, hda_nid_t cap2)
5537{
5538 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005539 struct hda_input_mux *imux = &spec->private_imux[0];
David Henningsson5322bf22011-01-05 11:03:56 +01005540 int i, err, idx, type_idx = 0;
5541 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005542
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005543 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005544 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005545 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005546
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005547 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005548 if (!alc_is_input_pin(codec, pin))
5549 continue;
5550
David Henningsson5322bf22011-01-05 11:03:56 +01005551 label = hda_get_autocfg_input_label(codec, cfg, i);
5552 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005553 type_idx++;
5554 else
5555 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005556 prev_label = label;
5557
Takashi Iwai05f5f472009-08-25 13:10:18 +02005558 if (mixer) {
5559 idx = get_connection_index(codec, mixer, pin);
5560 if (idx >= 0) {
5561 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005562 label, type_idx,
5563 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005564 if (err < 0)
5565 return err;
5566 }
5567 }
5568
5569 if (!cap1)
5570 continue;
5571 idx = get_connection_index(codec, cap1, pin);
5572 if (idx < 0 && cap2)
5573 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005574 if (idx >= 0)
5575 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005576 }
5577 return 0;
5578}
5579
Takashi Iwai05f5f472009-08-25 13:10:18 +02005580static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5581 const struct auto_pin_cfg *cfg)
5582{
5583 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5584}
5585
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005586static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5587 unsigned int pin_type)
5588{
5589 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5590 pin_type);
5591 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005592 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5593 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005594}
5595
Kailang Yangdf694da2005-12-05 19:42:22 +01005596static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
5597 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005598 int dac_idx)
5599{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005600 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005601 /* need the manual connection? */
5602 if (alc880_is_multi_pin(nid)) {
5603 struct alc_spec *spec = codec->spec;
5604 int idx = alc880_multi_pin_idx(nid);
5605 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
5606 AC_VERB_SET_CONNECT_SEL,
5607 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
5608 }
5609}
5610
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005611static int get_pin_type(int line_out_type)
5612{
5613 if (line_out_type == AUTO_PIN_HP_OUT)
5614 return PIN_HP;
5615 else
5616 return PIN_OUT;
5617}
5618
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005619static void alc880_auto_init_multi_out(struct hda_codec *codec)
5620{
5621 struct alc_spec *spec = codec->spec;
5622 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005623
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005624 for (i = 0; i < spec->autocfg.line_outs; i++) {
5625 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005626 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5627 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005628 }
5629}
5630
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005631static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005632{
5633 struct alc_spec *spec = codec->spec;
5634 hda_nid_t pin;
5635
Takashi Iwai82bc9552006-03-21 11:24:42 +01005636 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005637 if (pin) /* connect to front */
5638 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005639 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005640 if (pin) /* connect to front */
5641 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5642}
5643
5644static void alc880_auto_init_analog_input(struct hda_codec *codec)
5645{
5646 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005647 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005648 int i;
5649
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005650 for (i = 0; i < cfg->num_inputs; i++) {
5651 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005652 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005653 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005654 if (nid != ALC880_PIN_CD_NID &&
5655 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005656 snd_hda_codec_write(codec, nid, 0,
5657 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005658 AMP_OUT_MUTE);
5659 }
5660 }
5661}
5662
Takashi Iwai7f311a42010-04-09 17:32:23 +02005663static void alc880_auto_init_input_src(struct hda_codec *codec)
5664{
5665 struct alc_spec *spec = codec->spec;
5666 int c;
5667
5668 for (c = 0; c < spec->num_adc_nids; c++) {
5669 unsigned int mux_idx;
5670 const struct hda_input_mux *imux;
5671 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5672 imux = &spec->input_mux[mux_idx];
5673 if (!imux->num_items && mux_idx > 0)
5674 imux = &spec->input_mux[0];
5675 if (imux)
5676 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5677 AC_VERB_SET_CONNECT_SEL,
5678 imux->items[0].index);
5679 }
5680}
5681
Takashi Iwaice764ab2011-04-27 16:35:23 +02005682static int alc_auto_add_multi_channel_mode(struct hda_codec *codec);
5683
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005684/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005685/* return 1 if successful, 0 if the proper config is not found,
5686 * or a negative error code
5687 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005688static int alc880_parse_auto_config(struct hda_codec *codec)
5689{
5690 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005691 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005692 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005693
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005694 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5695 alc880_ignore);
5696 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005697 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005698 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005699 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005700
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005701 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5702 if (err < 0)
5703 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +02005704 err = alc_auto_add_multi_channel_mode(codec);
5705 if (err < 0)
5706 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005707 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5708 if (err < 0)
5709 return err;
5710 err = alc880_auto_create_extra_out(spec,
5711 spec->autocfg.speaker_pins[0],
5712 "Speaker");
5713 if (err < 0)
5714 return err;
5715 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5716 "Headphone");
5717 if (err < 0)
5718 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005719 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005720 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005721 return err;
5722
5723 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5724
Takashi Iwai757899a2010-07-30 10:48:14 +02005725 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005726
Takashi Iwai603c4012008-07-30 15:01:44 +02005727 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005728 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005729
Takashi Iwaid88897e2008-10-31 15:01:37 +01005730 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005731
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005732 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005733 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005734
Kailang Yang6227cdc2010-02-25 08:36:52 +01005735 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005736
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005737 return 1;
5738}
5739
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005740/* additional initialization for auto-configuration model */
5741static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005742{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005743 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005744 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005745 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005746 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005747 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005748 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005749 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005750 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005751}
5752
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005753/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5754 * one of two digital mic pins, e.g. on ALC272
5755 */
5756static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005757{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005758 struct alc_spec *spec = codec->spec;
5759 int i;
5760
5761 for (i = 0; i < spec->num_adc_nids; i++) {
5762 hda_nid_t cap = spec->capsrc_nids ?
5763 spec->capsrc_nids[i] : spec->adc_nids[i];
5764 int iidx, eidx;
5765
5766 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5767 if (iidx < 0)
5768 continue;
5769 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5770 if (eidx < 0)
5771 continue;
5772 spec->int_mic.mux_idx = iidx;
5773 spec->ext_mic.mux_idx = eidx;
5774 if (spec->capsrc_nids)
5775 spec->capsrc_nids += i;
5776 spec->adc_nids += i;
5777 spec->num_adc_nids = 1;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005778 /* optional dock-mic */
5779 eidx = get_connection_index(codec, cap, spec->dock_mic.pin);
5780 if (eidx < 0)
5781 spec->dock_mic.pin = 0;
5782 else
5783 spec->dock_mic.mux_idx = eidx;
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005784 return;
5785 }
5786 snd_printd(KERN_INFO "hda_codec: %s: "
5787 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5788 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5789 spec->auto_mic = 0; /* disable auto-mic to be sure */
5790}
5791
Takashi Iwai748cce42010-08-04 07:37:39 +02005792/* select or unmute the given capsrc route */
5793static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5794 int idx)
5795{
5796 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5797 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5798 HDA_AMP_MUTE, 0);
5799 } else {
5800 snd_hda_codec_write_cache(codec, cap, 0,
5801 AC_VERB_SET_CONNECT_SEL, idx);
5802 }
5803}
5804
Takashi Iwai840b64c2010-07-13 22:49:01 +02005805/* set the default connection to that pin */
5806static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5807{
5808 struct alc_spec *spec = codec->spec;
5809 int i;
5810
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005811 if (!pin)
5812 return 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005813 for (i = 0; i < spec->num_adc_nids; i++) {
5814 hda_nid_t cap = spec->capsrc_nids ?
5815 spec->capsrc_nids[i] : spec->adc_nids[i];
5816 int idx;
5817
5818 idx = get_connection_index(codec, cap, pin);
5819 if (idx < 0)
5820 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005821 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005822 return i; /* return the found index */
5823 }
5824 return -1; /* not found */
5825}
5826
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005827/* choose the ADC/MUX containing the input pin and initialize the setup */
5828static void fixup_single_adc(struct hda_codec *codec)
5829{
5830 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005831 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005832 int i;
5833
5834 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005835 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005836 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005837 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005838 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005839 /* use only this ADC */
5840 if (spec->capsrc_nids)
5841 spec->capsrc_nids += i;
5842 spec->adc_nids += i;
5843 spec->num_adc_nids = 1;
Takashi Iwai584c0c42011-03-10 12:51:11 +01005844 spec->single_input_src = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005845 }
5846}
5847
Takashi Iwai840b64c2010-07-13 22:49:01 +02005848/* initialize dual adcs */
5849static void fixup_dual_adc_switch(struct hda_codec *codec)
5850{
5851 struct alc_spec *spec = codec->spec;
5852 init_capsrc_for_pin(codec, spec->ext_mic.pin);
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005853 init_capsrc_for_pin(codec, spec->dock_mic.pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005854 init_capsrc_for_pin(codec, spec->int_mic.pin);
5855}
5856
Takashi Iwai584c0c42011-03-10 12:51:11 +01005857/* initialize some special cases for input sources */
5858static void alc_init_special_input_src(struct hda_codec *codec)
5859{
5860 struct alc_spec *spec = codec->spec;
5861 if (spec->dual_adc_switch)
5862 fixup_dual_adc_switch(codec);
5863 else if (spec->single_input_src)
5864 init_capsrc_for_pin(codec, spec->autocfg.inputs[0].pin);
5865}
5866
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005867static void set_capture_mixer(struct hda_codec *codec)
5868{
5869 struct alc_spec *spec = codec->spec;
Takashi Iwaia9111322011-05-02 11:30:18 +02005870 static const struct snd_kcontrol_new *caps[2][3] = {
Takashi Iwaia23b6882009-03-23 15:21:36 +01005871 { alc_capture_mixer_nosrc1,
5872 alc_capture_mixer_nosrc2,
5873 alc_capture_mixer_nosrc3 },
5874 { alc_capture_mixer1,
5875 alc_capture_mixer2,
5876 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005877 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005878 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005879 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005880 int num_adcs = spec->num_adc_nids;
5881 if (spec->dual_adc_switch)
Takashi Iwai584c0c42011-03-10 12:51:11 +01005882 num_adcs = 1;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005883 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005884 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005885 else if (spec->input_mux) {
5886 if (spec->input_mux->num_items > 1)
5887 mux = 1;
5888 else if (spec->input_mux->num_items == 1)
5889 fixup_single_adc(codec);
5890 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005891 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005892 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005893}
5894
Takashi Iwai66946352010-03-29 17:21:45 +02005895/* fill adc_nids (and capsrc_nids) containing all active input pins */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005896static void fillup_priv_adc_nids(struct hda_codec *codec, const hda_nid_t *nids,
Takashi Iwai66946352010-03-29 17:21:45 +02005897 int num_nids)
5898{
5899 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005900 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005901 int n;
5902 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5903
5904 for (n = 0; n < num_nids; n++) {
5905 hda_nid_t adc, cap;
5906 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5907 int nconns, i, j;
5908
5909 adc = nids[n];
5910 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5911 continue;
5912 cap = adc;
5913 nconns = snd_hda_get_connections(codec, cap, conn,
5914 ARRAY_SIZE(conn));
5915 if (nconns == 1) {
5916 cap = conn[0];
5917 nconns = snd_hda_get_connections(codec, cap, conn,
5918 ARRAY_SIZE(conn));
5919 }
5920 if (nconns <= 0)
5921 continue;
5922 if (!fallback_adc) {
5923 fallback_adc = adc;
5924 fallback_cap = cap;
5925 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005926 for (i = 0; i < cfg->num_inputs; i++) {
5927 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005928 for (j = 0; j < nconns; j++) {
5929 if (conn[j] == nid)
5930 break;
5931 }
5932 if (j >= nconns)
5933 break;
5934 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005935 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005936 int num_adcs = spec->num_adc_nids;
5937 spec->private_adc_nids[num_adcs] = adc;
5938 spec->private_capsrc_nids[num_adcs] = cap;
5939 spec->num_adc_nids++;
5940 spec->adc_nids = spec->private_adc_nids;
5941 if (adc != cap)
5942 spec->capsrc_nids = spec->private_capsrc_nids;
5943 }
5944 }
5945 if (!spec->num_adc_nids) {
5946 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005947 " using fallback 0x%x\n",
5948 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005949 spec->private_adc_nids[0] = fallback_adc;
5950 spec->adc_nids = spec->private_adc_nids;
5951 if (fallback_adc != fallback_cap) {
5952 spec->private_capsrc_nids[0] = fallback_cap;
5953 spec->capsrc_nids = spec->private_adc_nids;
5954 }
5955 }
5956}
5957
Takashi Iwai67d634c2009-11-16 15:35:59 +01005958#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005959#define set_beep_amp(spec, nid, idx, dir) \
5960 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005961
Takashi Iwaia9111322011-05-02 11:30:18 +02005962static const struct snd_pci_quirk beep_white_list[] = {
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005963 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005964 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Daniel Corderoa7e985e2011-04-29 08:18:06 +02005965 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
Madis Janson39dfe132011-05-19 18:32:41 +02005966 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005967 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005968 {}
5969};
5970
5971static inline int has_cdefine_beep(struct hda_codec *codec)
5972{
5973 struct alc_spec *spec = codec->spec;
5974 const struct snd_pci_quirk *q;
5975 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5976 if (q)
5977 return q->value;
5978 return spec->cdefine.enable_pcbeep;
5979}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005980#else
5981#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005982#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005983#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005984
5985/*
5986 * OK, here we have finally the patch for ALC880
5987 */
5988
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989static int patch_alc880(struct hda_codec *codec)
5990{
5991 struct alc_spec *spec;
5992 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005993 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005995 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996 if (spec == NULL)
5997 return -ENOMEM;
5998
5999 codec->spec = spec;
6000
Takashi Iwaif5fcc132006-11-24 17:07:44 +01006001 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
6002 alc880_models,
6003 alc880_cfg_tbl);
6004 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02006005 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
6006 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006007 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008 }
6009
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006010 if (board_config == ALC880_AUTO) {
6011 /* automatic parse from the BIOS config */
6012 err = alc880_parse_auto_config(codec);
6013 if (err < 0) {
6014 alc_free(codec);
6015 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006016 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02006017 printk(KERN_INFO
6018 "hda_codec: Cannot set up configuration "
6019 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006020 board_config = ALC880_3ST;
6021 }
6022 }
6023
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09006024 err = snd_hda_attach_beep_device(codec, 0x1);
6025 if (err < 0) {
6026 alc_free(codec);
6027 return err;
6028 }
6029
Kailang Yangdf694da2005-12-05 19:42:22 +01006030 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02006031 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033 spec->stream_analog_playback = &alc880_pcm_analog_playback;
6034 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01006035 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037 spec->stream_digital_playback = &alc880_pcm_digital_playback;
6038 spec->stream_digital_capture = &alc880_pcm_digital_capture;
6039
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006040 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006041 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01006042 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006043 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02006044 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006045 if (wcap != AC_WID_AUD_IN) {
6046 spec->adc_nids = alc880_adc_nids_alt;
6047 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006048 } else {
6049 spec->adc_nids = alc880_adc_nids;
6050 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006051 }
6052 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02006053 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01006054 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055
Takashi Iwai2134ea42008-01-10 16:53:55 +01006056 spec->vmaster_nid = 0x0c;
6057
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006059 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01006060 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02006061#ifdef CONFIG_SND_HDA_POWER_SAVE
6062 if (!spec->loopback.amplist)
6063 spec->loopback.amplist = alc880_loopbacks;
6064#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065
6066 return 0;
6067}
6068
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006069
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070/*
6071 * ALC260 support
6072 */
6073
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006074static const hda_nid_t alc260_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006075 /* front */
6076 0x02,
6077};
6078
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006079static const hda_nid_t alc260_adc_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006080 /* ADC0 */
6081 0x04,
6082};
6083
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006084static const hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006085 /* ADC1 */
6086 0x05,
6087};
6088
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006089/* NIDs used when simultaneous access to both ADCs makes sense. Note that
6090 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
6091 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006092static const hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006093 /* ADC0, ADC1 */
6094 0x04, 0x05
6095};
6096
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006097#define ALC260_DIGOUT_NID 0x03
6098#define ALC260_DIGIN_NID 0x06
6099
Takashi Iwaia9111322011-05-02 11:30:18 +02006100static const struct hda_input_mux alc260_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006101 .num_items = 4,
6102 .items = {
6103 { "Mic", 0x0 },
6104 { "Front Mic", 0x1 },
6105 { "Line", 0x2 },
6106 { "CD", 0x4 },
6107 },
6108};
6109
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006110/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006111 * headphone jack and the internal CD lines since these are the only pins at
6112 * which audio can appear. For flexibility, also allow the option of
6113 * recording the mixer output on the second ADC (ADC0 doesn't have a
6114 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006115 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006116static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006117 {
6118 .num_items = 3,
6119 .items = {
6120 { "Mic/Line", 0x0 },
6121 { "CD", 0x4 },
6122 { "Headphone", 0x2 },
6123 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006124 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006125 {
6126 .num_items = 4,
6127 .items = {
6128 { "Mic/Line", 0x0 },
6129 { "CD", 0x4 },
6130 { "Headphone", 0x2 },
6131 { "Mixer", 0x5 },
6132 },
6133 },
6134
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006135};
6136
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006137/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
6138 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006139 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006140static const struct hda_input_mux alc260_acer_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006141 {
6142 .num_items = 4,
6143 .items = {
6144 { "Mic", 0x0 },
6145 { "Line", 0x2 },
6146 { "CD", 0x4 },
6147 { "Headphone", 0x5 },
6148 },
6149 },
6150 {
6151 .num_items = 5,
6152 .items = {
6153 { "Mic", 0x0 },
6154 { "Line", 0x2 },
6155 { "CD", 0x4 },
6156 { "Headphone", 0x6 },
6157 { "Mixer", 0x5 },
6158 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006159 },
6160};
Michael Schwingencc959482009-02-22 18:58:45 +01006161
6162/* Maxdata Favorit 100XS */
Takashi Iwaia9111322011-05-02 11:30:18 +02006163static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006164 {
6165 .num_items = 2,
6166 .items = {
6167 { "Line/Mic", 0x0 },
6168 { "CD", 0x4 },
6169 },
6170 },
6171 {
6172 .num_items = 3,
6173 .items = {
6174 { "Line/Mic", 0x0 },
6175 { "CD", 0x4 },
6176 { "Mixer", 0x5 },
6177 },
6178 },
6179};
6180
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181/*
6182 * This is just place-holder, so there's something for alc_build_pcms to look
6183 * at when it calculates the maximum number of channels. ALC260 has no mixer
6184 * element which allows changing the channel mode, so the verb list is
6185 * never used.
6186 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006187static const struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188 { 2, NULL },
6189};
6190
Kailang Yangdf694da2005-12-05 19:42:22 +01006191
6192/* Mixer combinations
6193 *
6194 * basic: base_output + input + pc_beep + capture
6195 * HP: base_output + input + capture_alt
6196 * HP_3013: hp_3013 + input + capture
6197 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006198 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01006199 */
6200
Takashi Iwaia9111322011-05-02 11:30:18 +02006201static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006202 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006203 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006204 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6205 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6206 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6207 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6208 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006209};
Kailang Yangdf694da2005-12-05 19:42:22 +01006210
Takashi Iwaia9111322011-05-02 11:30:18 +02006211static const struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6213 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6214 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6215 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6216 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6217 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6218 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
6219 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006220 { } /* end */
6221};
6222
Takashi Iwaibec15c32008-01-28 18:16:30 +01006223/* update HP, line and mono out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +02006224static void alc260_hp_master_update(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006225{
Takashi Iwaie9427962011-04-28 15:46:07 +02006226 update_speakers(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006227}
6228
6229static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
6230 struct snd_ctl_elem_value *ucontrol)
6231{
6232 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6233 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006234 *ucontrol->value.integer.value = !spec->master_mute;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006235 return 0;
6236}
6237
6238static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
6239 struct snd_ctl_elem_value *ucontrol)
6240{
6241 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6242 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006243 int val = !*ucontrol->value.integer.value;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006244
Takashi Iwaie9427962011-04-28 15:46:07 +02006245 if (val == spec->master_mute)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006246 return 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02006247 spec->master_mute = val;
6248 alc260_hp_master_update(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006249 return 1;
6250}
6251
Takashi Iwaia9111322011-05-02 11:30:18 +02006252static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006253 {
6254 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6255 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006256 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006257 .info = snd_ctl_boolean_mono_info,
6258 .get = alc260_hp_master_sw_get,
6259 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006260 },
6261 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6262 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
6263 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6264 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6265 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
6266 HDA_OUTPUT),
6267 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6268 { } /* end */
6269};
6270
Takashi Iwaia9111322011-05-02 11:30:18 +02006271static const struct hda_verb alc260_hp_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006272 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6273 {},
6274};
6275
Takashi Iwaie9427962011-04-28 15:46:07 +02006276static void alc260_hp_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006277{
6278 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006279
Takashi Iwaie9427962011-04-28 15:46:07 +02006280 spec->autocfg.hp_pins[0] = 0x0f;
6281 spec->autocfg.speaker_pins[0] = 0x10;
6282 spec->autocfg.speaker_pins[1] = 0x11;
6283 spec->automute = 1;
6284 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006285}
6286
Takashi Iwaia9111322011-05-02 11:30:18 +02006287static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006288 {
6289 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6290 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006291 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006292 .info = snd_ctl_boolean_mono_info,
6293 .get = alc260_hp_master_sw_get,
6294 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006295 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006296 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6297 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6298 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
6299 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
6300 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6301 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006302 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6303 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02006304 { } /* end */
6305};
6306
Takashi Iwaie9427962011-04-28 15:46:07 +02006307static void alc260_hp_3013_setup(struct hda_codec *codec)
6308{
6309 struct alc_spec *spec = codec->spec;
6310
6311 spec->autocfg.hp_pins[0] = 0x15;
6312 spec->autocfg.speaker_pins[0] = 0x10;
6313 spec->autocfg.speaker_pins[1] = 0x11;
6314 spec->automute = 1;
6315 spec->automute_mode = ALC_AUTOMUTE_PIN;
6316}
6317
Takashi Iwaia9111322011-05-02 11:30:18 +02006318static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
Kailang Yang3f878302008-08-26 13:02:23 +02006319 .ops = &snd_hda_bind_vol,
6320 .values = {
6321 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
6322 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
6323 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
6324 0
6325 },
6326};
6327
Takashi Iwaia9111322011-05-02 11:30:18 +02006328static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
Kailang Yang3f878302008-08-26 13:02:23 +02006329 .ops = &snd_hda_bind_sw,
6330 .values = {
6331 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
6332 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
6333 0
6334 },
6335};
6336
Takashi Iwaia9111322011-05-02 11:30:18 +02006337static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006338 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
6339 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
6340 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
6341 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6342 { } /* end */
6343};
6344
Takashi Iwaia9111322011-05-02 11:30:18 +02006345static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006346 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6347 {},
6348};
6349
Takashi Iwaie9427962011-04-28 15:46:07 +02006350static void alc260_hp_3012_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006351{
6352 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006353
Takashi Iwaie9427962011-04-28 15:46:07 +02006354 spec->autocfg.hp_pins[0] = 0x10;
6355 spec->autocfg.speaker_pins[0] = 0x0f;
6356 spec->autocfg.speaker_pins[1] = 0x11;
6357 spec->autocfg.speaker_pins[2] = 0x15;
6358 spec->automute = 1;
6359 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang3f878302008-08-26 13:02:23 +02006360}
6361
6362/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006363 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6364 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006365static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006366 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006367 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006368 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006369 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6370 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6371 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6372 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006373 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006374 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6375 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006376 { } /* end */
6377};
6378
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006379/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6380 * versions of the ALC260 don't act on requests to enable mic bias from NID
6381 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6382 * datasheet doesn't mention this restriction. At this stage it's not clear
6383 * whether this behaviour is intentional or is a hardware bug in chip
6384 * revisions available in early 2006. Therefore for now allow the
6385 * "Headphone Jack Mode" control to span all choices, but if it turns out
6386 * that the lack of mic bias for this NID is intentional we could change the
6387 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6388 *
6389 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6390 * don't appear to make the mic bias available from the "line" jack, even
6391 * though the NID used for this jack (0x14) can supply it. The theory is
6392 * that perhaps Acer have included blocking capacitors between the ALC260
6393 * and the output jack. If this turns out to be the case for all such
6394 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6395 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006396 *
6397 * The C20x Tablet series have a mono internal speaker which is controlled
6398 * via the chip's Mono sum widget and pin complex, so include the necessary
6399 * controls for such models. On models without a "mono speaker" the control
6400 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006401 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006402static const struct snd_kcontrol_new alc260_acer_mixer[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006403 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6404 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006405 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006406 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006407 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006408 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006409 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006410 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6411 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6412 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6413 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6414 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6415 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6416 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6417 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006418 { } /* end */
6419};
6420
Michael Schwingencc959482009-02-22 18:58:45 +01006421/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6422 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006423static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006424 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6425 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6426 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6427 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6428 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6429 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6430 { } /* end */
6431};
6432
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006433/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6434 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6435 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006436static const struct snd_kcontrol_new alc260_will_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006437 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6438 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6439 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6440 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6441 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6442 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6443 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6444 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6445 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6446 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006447 { } /* end */
6448};
6449
6450/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6451 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6452 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006453static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006454 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6455 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6456 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6457 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6458 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6459 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6460 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6461 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6462 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6463 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6464 { } /* end */
6465};
6466
Kailang Yangdf694da2005-12-05 19:42:22 +01006467/*
6468 * initialization verbs
6469 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006470static const struct hda_verb alc260_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006472 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006474 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006476 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006478 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006480 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006482 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006484 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006486 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006488 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6489 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006490 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 /* set connection select to line in (default select for this ADC) */
6492 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006493 /* mute capture amp left and right */
6494 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6495 /* set connection select to line in (default select for this ADC) */
6496 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006497 /* set vol=0 Line-Out mixer amp left and right */
6498 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6499 /* unmute pin widget amp left and right (no gain on this amp) */
6500 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6501 /* set vol=0 HP mixer amp left and right */
6502 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6503 /* unmute pin widget amp left and right (no gain on this amp) */
6504 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6505 /* set vol=0 Mono mixer amp left and right */
6506 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6507 /* unmute pin widget amp left and right (no gain on this amp) */
6508 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6509 /* unmute LINE-2 out pin */
6510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006511 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6512 * Line In 2 = 0x03
6513 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006514 /* mute analog inputs */
6515 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6516 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6517 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6518 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6519 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006520 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006521 /* mute Front out path */
6522 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6523 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6524 /* mute Headphone out path */
6525 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6526 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6527 /* mute Mono out path */
6528 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6529 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530 { }
6531};
6532
Takashi Iwai474167d2006-05-17 17:17:43 +02006533#if 0 /* should be identical with alc260_init_verbs? */
Takashi Iwaia9111322011-05-02 11:30:18 +02006534static const struct hda_verb alc260_hp_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006535 /* Headphone and output */
6536 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6537 /* mono output */
6538 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6539 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6540 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6541 /* Mic2 (front panel) pin widget for input and vref at 80% */
6542 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6543 /* Line In pin widget for input */
6544 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6545 /* Line-2 pin widget for output */
6546 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6547 /* CD pin widget for input */
6548 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6549 /* unmute amp left and right */
6550 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6551 /* set connection select to line in (default select for this ADC) */
6552 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6553 /* unmute Line-Out mixer amp left and right (volume = 0) */
6554 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6555 /* mute pin widget amp left and right (no gain on this amp) */
6556 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6557 /* unmute HP mixer amp left and right (volume = 0) */
6558 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6559 /* mute pin widget amp left and right (no gain on this amp) */
6560 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006561 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6562 * Line In 2 = 0x03
6563 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006564 /* mute analog inputs */
6565 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6566 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6567 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6568 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6569 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006570 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6571 /* Unmute Front out path */
6572 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6573 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6574 /* Unmute Headphone out path */
6575 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6576 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6577 /* Unmute Mono out path */
6578 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6579 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6580 { }
6581};
Takashi Iwai474167d2006-05-17 17:17:43 +02006582#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006583
Takashi Iwaia9111322011-05-02 11:30:18 +02006584static const struct hda_verb alc260_hp_3013_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006585 /* Line out and output */
6586 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6587 /* mono output */
6588 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6589 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6590 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6591 /* Mic2 (front panel) pin widget for input and vref at 80% */
6592 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6593 /* Line In pin widget for input */
6594 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6595 /* Headphone pin widget for output */
6596 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6597 /* CD pin widget for input */
6598 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6599 /* unmute amp left and right */
6600 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6601 /* set connection select to line in (default select for this ADC) */
6602 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6603 /* unmute Line-Out mixer amp left and right (volume = 0) */
6604 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6605 /* mute pin widget amp left and right (no gain on this amp) */
6606 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6607 /* unmute HP mixer amp left and right (volume = 0) */
6608 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6609 /* mute pin widget amp left and right (no gain on this amp) */
6610 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006611 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6612 * Line In 2 = 0x03
6613 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006614 /* mute analog inputs */
6615 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6616 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6617 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6618 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6619 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006620 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6621 /* Unmute Front out path */
6622 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6623 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6624 /* Unmute Headphone out path */
6625 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6626 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6627 /* Unmute Mono out path */
6628 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6629 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6630 { }
6631};
6632
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006633/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006634 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6635 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006636 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006637static const struct hda_verb alc260_fujitsu_init_verbs[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006638 /* Disable all GPIOs */
6639 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6640 /* Internal speaker is connected to headphone pin */
6641 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6642 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6643 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006644 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6645 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6646 /* Ensure all other unused pins are disabled and muted. */
6647 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6648 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006649 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006650 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006651 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006652 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6653 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6654 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006655
Jonathan Woithef7ace402006-02-28 11:46:14 +01006656 /* Disable digital (SPDIF) pins */
6657 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6658 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006659
Kailang Yangea1fb292008-08-26 12:58:38 +02006660 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006661 * when acting as an output.
6662 */
6663 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6664
6665 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006666 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6667 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6668 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6669 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6670 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6671 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6672 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6673 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6674 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006675
Jonathan Woithef7ace402006-02-28 11:46:14 +01006676 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6677 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6678 /* Unmute Line1 pin widget output buffer since it starts as an output.
6679 * If the pin mode is changed by the user the pin mode control will
6680 * take care of enabling the pin's input/output buffers as needed.
6681 * Therefore there's no need to enable the input buffer at this
6682 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006683 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006684 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006685 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006686 * mixer ctrl)
6687 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006688 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006689
Jonathan Woithef7ace402006-02-28 11:46:14 +01006690 /* Mute capture amp left and right */
6691 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006692 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006693 * in (on mic1 pin)
6694 */
6695 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006696
Jonathan Woithef7ace402006-02-28 11:46:14 +01006697 /* Do the same for the second ADC: mute capture input amp and
6698 * set ADC connection to line in (on mic1 pin)
6699 */
6700 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6701 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006702
Jonathan Woithef7ace402006-02-28 11:46:14 +01006703 /* 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 */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006712
6713 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006714};
6715
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006716/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6717 * similar laptops (adapted from Fujitsu init verbs).
6718 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006719static const struct hda_verb alc260_acer_init_verbs[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006720 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6721 * the headphone jack. Turn this on and rely on the standard mute
6722 * methods whenever the user wants to turn these outputs off.
6723 */
6724 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6725 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6726 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6727 /* Internal speaker/Headphone jack is connected to Line-out pin */
6728 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6729 /* Internal microphone/Mic jack is connected to Mic1 pin */
6730 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6731 /* Line In jack is connected to Line1 pin */
6732 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006733 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6734 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006735 /* Ensure all other unused pins are disabled and muted. */
6736 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6737 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006738 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6739 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6740 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6741 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6742 /* Disable digital (SPDIF) pins */
6743 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6744 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6745
Kailang Yangea1fb292008-08-26 12:58:38 +02006746 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006747 * bus when acting as outputs.
6748 */
6749 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6750 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6751
6752 /* Start with output sum widgets muted and their output gains at min */
6753 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6754 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6755 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6756 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6757 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6758 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6759 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6760 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6761 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6762
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006763 /* Unmute Line-out pin widget amp left and right
6764 * (no equiv mixer ctrl)
6765 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006766 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006767 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6768 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006769 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6770 * inputs. If the pin mode is changed by the user the pin mode control
6771 * will take care of enabling the pin's input/output buffers as needed.
6772 * Therefore there's no need to enable the input buffer at this
6773 * stage.
6774 */
6775 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6776 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6777
6778 /* Mute capture amp left and right */
6779 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6780 /* Set ADC connection select to match default mixer setting - mic
6781 * (on mic1 pin)
6782 */
6783 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6784
6785 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006786 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006787 */
6788 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006789 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006790
6791 /* Mute all inputs to mixer widget (even unconnected ones) */
6792 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6793 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6794 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6795 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6796 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6797 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6798 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6799 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6800
6801 { }
6802};
6803
Michael Schwingencc959482009-02-22 18:58:45 +01006804/* Initialisation sequence for Maxdata Favorit 100XS
6805 * (adapted from Acer init verbs).
6806 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006807static const struct hda_verb alc260_favorit100_init_verbs[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006808 /* GPIO 0 enables the output jack.
6809 * Turn this on and rely on the standard mute
6810 * methods whenever the user wants to turn these outputs off.
6811 */
6812 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6813 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6814 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6815 /* Line/Mic input jack is connected to Mic1 pin */
6816 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6817 /* Ensure all other unused pins are disabled and muted. */
6818 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6819 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6820 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6821 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6822 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6823 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6824 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6825 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6826 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6827 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6828 /* Disable digital (SPDIF) pins */
6829 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6830 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6831
6832 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6833 * bus when acting as outputs.
6834 */
6835 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6836 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6837
6838 /* Start with output sum widgets muted and their output gains at min */
6839 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6840 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6841 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6842 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6843 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6844 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6845 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6846 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6847 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6848
6849 /* Unmute Line-out pin widget amp left and right
6850 * (no equiv mixer ctrl)
6851 */
6852 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6853 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6854 * inputs. If the pin mode is changed by the user the pin mode control
6855 * will take care of enabling the pin's input/output buffers as needed.
6856 * Therefore there's no need to enable the input buffer at this
6857 * stage.
6858 */
6859 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6860
6861 /* Mute capture amp left and right */
6862 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6863 /* Set ADC connection select to match default mixer setting - mic
6864 * (on mic1 pin)
6865 */
6866 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6867
6868 /* Do similar with the second ADC: mute capture input amp and
6869 * set ADC connection to mic to match ALSA's default state.
6870 */
6871 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6872 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6873
6874 /* Mute all inputs to mixer widget (even unconnected ones) */
6875 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6876 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6877 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6878 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6879 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6880 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6881 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6882 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6883
6884 { }
6885};
6886
Takashi Iwaia9111322011-05-02 11:30:18 +02006887static const struct hda_verb alc260_will_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006888 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6889 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6890 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6891 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6892 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6893 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6894 {}
6895};
6896
Takashi Iwaia9111322011-05-02 11:30:18 +02006897static const struct hda_verb alc260_replacer_672v_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006898 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6899 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6900 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6901
6902 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6903 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6904 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6905
6906 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6907 {}
6908};
6909
6910/* toggle speaker-output according to the hp-jack state */
6911static void alc260_replacer_672v_automute(struct hda_codec *codec)
6912{
6913 unsigned int present;
6914
6915 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006916 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006917 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006918 snd_hda_codec_write_cache(codec, 0x01, 0,
6919 AC_VERB_SET_GPIO_DATA, 1);
6920 snd_hda_codec_write_cache(codec, 0x0f, 0,
6921 AC_VERB_SET_PIN_WIDGET_CONTROL,
6922 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006923 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006924 snd_hda_codec_write_cache(codec, 0x01, 0,
6925 AC_VERB_SET_GPIO_DATA, 0);
6926 snd_hda_codec_write_cache(codec, 0x0f, 0,
6927 AC_VERB_SET_PIN_WIDGET_CONTROL,
6928 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006929 }
6930}
6931
6932static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6933 unsigned int res)
6934{
6935 if ((res >> 26) == ALC880_HP_EVENT)
6936 alc260_replacer_672v_automute(codec);
6937}
6938
Takashi Iwaia9111322011-05-02 11:30:18 +02006939static const struct hda_verb alc260_hp_dc7600_verbs[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006940 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6941 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6942 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6943 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6944 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6945 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6946 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6947 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6948 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6949 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6950 {}
6951};
6952
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006953/* Test configuration for debugging, modelled after the ALC880 test
6954 * configuration.
6955 */
6956#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006957static const hda_nid_t alc260_test_dac_nids[1] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006958 0x02,
6959};
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006960static const hda_nid_t alc260_test_adc_nids[2] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006961 0x04, 0x05,
6962};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006963/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006964 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006965 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006966 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006967static const struct hda_input_mux alc260_test_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006968 {
6969 .num_items = 7,
6970 .items = {
6971 { "MIC1 pin", 0x0 },
6972 { "MIC2 pin", 0x1 },
6973 { "LINE1 pin", 0x2 },
6974 { "LINE2 pin", 0x3 },
6975 { "CD pin", 0x4 },
6976 { "LINE-OUT pin", 0x5 },
6977 { "HP-OUT pin", 0x6 },
6978 },
6979 },
6980 {
6981 .num_items = 8,
6982 .items = {
6983 { "MIC1 pin", 0x0 },
6984 { "MIC2 pin", 0x1 },
6985 { "LINE1 pin", 0x2 },
6986 { "LINE2 pin", 0x3 },
6987 { "CD pin", 0x4 },
6988 { "Mixer", 0x5 },
6989 { "LINE-OUT pin", 0x6 },
6990 { "HP-OUT pin", 0x7 },
6991 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006992 },
6993};
Takashi Iwaia9111322011-05-02 11:30:18 +02006994static const struct snd_kcontrol_new alc260_test_mixer[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006995 /* Output driver widgets */
6996 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6997 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6998 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6999 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
7000 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
7001 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
7002
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007003 /* Modes for retasking pin widgets
7004 * Note: the ALC260 doesn't seem to act on requests to enable mic
7005 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
7006 * mention this restriction. At this stage it's not clear whether
7007 * this behaviour is intentional or is a hardware bug in chip
7008 * revisions available at least up until early 2006. Therefore for
7009 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
7010 * choices, but if it turns out that the lack of mic bias for these
7011 * NIDs is intentional we could change their modes from
7012 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
7013 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007014 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
7015 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
7016 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
7017 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
7018 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
7019 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
7020
7021 /* Loopback mixer controls */
7022 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
7023 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
7024 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
7025 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
7026 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
7027 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
7028 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
7029 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
7030 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
7031 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007032 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
7033 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
7034 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
7035 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01007036
7037 /* Controls for GPIO pins, assuming they are configured as outputs */
7038 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
7039 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
7040 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
7041 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
7042
Jonathan Woithe92621f12006-02-28 11:47:47 +01007043 /* Switches to allow the digital IO pins to be enabled. The datasheet
7044 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02007045 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01007046 */
7047 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
7048 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
7049
Jonathan Woithef8225f62008-01-08 12:16:54 +01007050 /* A switch allowing EAPD to be enabled. Some laptops seem to use
7051 * this output to turn on an external amplifier.
7052 */
7053 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
7054 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
7055
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007056 { } /* end */
7057};
Takashi Iwaia9111322011-05-02 11:30:18 +02007058static const struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01007059 /* Enable all GPIOs as outputs with an initial value of 0 */
7060 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
7061 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
7062 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
7063
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007064 /* Enable retasking pins as output, initially without power amp */
7065 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7066 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7067 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7068 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7069 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7070 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7071
Jonathan Woithe92621f12006-02-28 11:47:47 +01007072 /* Disable digital (SPDIF) pins initially, but users can enable
7073 * them via a mixer switch. In the case of SPDIF-out, this initverb
7074 * payload also sets the generation to 0, output to be in "consumer"
7075 * PCM format, copyright asserted, no pre-emphasis and no validity
7076 * control.
7077 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007078 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
7079 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
7080
Kailang Yangea1fb292008-08-26 12:58:38 +02007081 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007082 * OUT1 sum bus when acting as an output.
7083 */
7084 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
7085 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
7086 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
7087 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
7088
7089 /* Start with output sum widgets muted and their output gains at min */
7090 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7091 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7092 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7093 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7094 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7095 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7096 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7097 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7098 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7099
Jonathan Woithecdcd9262006-02-28 11:36:42 +01007100 /* Unmute retasking pin widget output buffers since the default
7101 * state appears to be output. As the pin mode is changed by the
7102 * user the pin mode control will take care of enabling the pin's
7103 * input/output buffers as needed.
7104 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007105 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7106 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7107 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7108 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7109 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7110 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7111 /* Also unmute the mono-out pin widget */
7112 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7113
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007114 /* Mute capture amp left and right */
7115 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01007116 /* Set ADC connection select to match default mixer setting (mic1
7117 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007118 */
7119 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
7120
7121 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01007122 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007123 */
7124 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7125 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
7126
7127 /* Mute all inputs to mixer widget (even unconnected ones) */
7128 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
7129 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
7130 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
7131 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
7132 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
7133 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
7134 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
7135 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
7136
7137 { }
7138};
7139#endif
7140
Takashi Iwai63300792008-01-24 15:31:36 +01007141#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
7142#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007144#define alc260_pcm_digital_playback alc880_pcm_digital_playback
7145#define alc260_pcm_digital_capture alc880_pcm_digital_capture
7146
Kailang Yangdf694da2005-12-05 19:42:22 +01007147/*
7148 * for BIOS auto-configuration
7149 */
7150
7151static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02007152 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01007153{
7154 hda_nid_t nid_vol;
7155 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01007156 int err;
7157
7158 if (nid >= 0x0f && nid < 0x11) {
7159 nid_vol = nid - 0x7;
7160 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
7161 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
7162 } else if (nid == 0x11) {
7163 nid_vol = nid - 0x7;
7164 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
7165 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
7166 } else if (nid >= 0x12 && nid <= 0x15) {
7167 nid_vol = 0x08;
7168 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
7169 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
7170 } else
7171 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02007172
Takashi Iwai863b4512008-10-21 17:01:47 +02007173 if (!(*vol_bits & (1 << nid_vol))) {
7174 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007175 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02007176 if (err < 0)
7177 return err;
7178 *vol_bits |= (1 << nid_vol);
7179 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007180 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007181 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007182 return err;
7183 return 1;
7184}
7185
7186/* add playback controls from the parsed DAC table */
7187static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
7188 const struct auto_pin_cfg *cfg)
7189{
7190 hda_nid_t nid;
7191 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02007192 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007193
7194 spec->multiout.num_dacs = 1;
7195 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +02007196 spec->private_dac_nids[0] = 0x02;
Kailang Yangdf694da2005-12-05 19:42:22 +01007197
7198 nid = cfg->line_out_pins[0];
7199 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02007200 const char *pfx;
7201 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
7202 pfx = "Master";
7203 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
7204 pfx = "Speaker";
7205 else
7206 pfx = "Front";
7207 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007208 if (err < 0)
7209 return err;
7210 }
7211
Takashi Iwai82bc9552006-03-21 11:24:42 +01007212 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007213 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007214 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007215 if (err < 0)
7216 return err;
7217 }
7218
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007219 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007220 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007221 err = alc260_add_playback_controls(spec, nid, "Headphone",
7222 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007223 if (err < 0)
7224 return err;
7225 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007226 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007227}
7228
7229/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007230static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01007231 const struct auto_pin_cfg *cfg)
7232{
Takashi Iwai05f5f472009-08-25 13:10:18 +02007233 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01007234}
7235
7236static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
7237 hda_nid_t nid, int pin_type,
7238 int sel_idx)
7239{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007240 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007241 /* need the manual connection? */
7242 if (nid >= 0x12) {
7243 int idx = nid - 0x12;
7244 snd_hda_codec_write(codec, idx + 0x0b, 0,
7245 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01007246 }
7247}
7248
7249static void alc260_auto_init_multi_out(struct hda_codec *codec)
7250{
7251 struct alc_spec *spec = codec->spec;
7252 hda_nid_t nid;
7253
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007254 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007255 if (nid) {
7256 int pin_type = get_pin_type(spec->autocfg.line_out_type);
7257 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
7258 }
Kailang Yangea1fb292008-08-26 12:58:38 +02007259
Takashi Iwai82bc9552006-03-21 11:24:42 +01007260 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007261 if (nid)
7262 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
7263
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007264 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007265 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007266 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007267}
Kailang Yangdf694da2005-12-05 19:42:22 +01007268
7269#define ALC260_PIN_CD_NID 0x16
7270static void alc260_auto_init_analog_input(struct hda_codec *codec)
7271{
7272 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007273 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +01007274 int i;
7275
Takashi Iwai66ceeb62010-08-30 13:05:52 +02007276 for (i = 0; i < cfg->num_inputs; i++) {
7277 hda_nid_t nid = cfg->inputs[i].pin;
Kailang Yangdf694da2005-12-05 19:42:22 +01007278 if (nid >= 0x12) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02007279 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01007280 if (nid != ALC260_PIN_CD_NID &&
7281 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007282 snd_hda_codec_write(codec, nid, 0,
7283 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01007284 AMP_OUT_MUTE);
7285 }
7286 }
7287}
7288
Takashi Iwai7f311a42010-04-09 17:32:23 +02007289#define alc260_auto_init_input_src alc880_auto_init_input_src
7290
Kailang Yangdf694da2005-12-05 19:42:22 +01007291/*
7292 * generic initialization of ADC, input mixers and output mixers
7293 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007294static const struct hda_verb alc260_volume_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007295 /*
7296 * Unmute ADC0-1 and set the default input to mic-in
7297 */
7298 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
7299 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7300 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
7301 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007302
Kailang Yangdf694da2005-12-05 19:42:22 +01007303 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
7304 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007305 * Note: PASD motherboards uses the Line In 2 as the input for
7306 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01007307 */
7308 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02007309 /* mute analog inputs */
7310 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7311 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7312 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
7313 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
7314 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01007315
7316 /*
7317 * Set up output mixers (0x08 - 0x0a)
7318 */
7319 /* set vol=0 to output mixers */
7320 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7321 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7322 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7323 /* set up input amps for analog loopback */
7324 /* Amp Indices: DAC = 0, mixer = 1 */
7325 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7326 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7327 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7328 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7329 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7330 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007331
Kailang Yangdf694da2005-12-05 19:42:22 +01007332 { }
7333};
7334
7335static int alc260_parse_auto_config(struct hda_codec *codec)
7336{
7337 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007338 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007339 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +01007340
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007341 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7342 alc260_ignore);
7343 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007344 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007345 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7346 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007347 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007348 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007349 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007350 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007351 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007352 return err;
7353
7354 spec->multiout.max_channels = 2;
7355
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007356 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007357 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007358 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007359 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007360
Takashi Iwaid88897e2008-10-31 15:01:37 +01007361 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01007362
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007363 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007364 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007365
Kailang Yang6227cdc2010-02-25 08:36:52 +01007366 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007367
Kailang Yangdf694da2005-12-05 19:42:22 +01007368 return 1;
7369}
7370
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007371/* additional initialization for auto-configuration model */
7372static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007373{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007374 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007375 alc260_auto_init_multi_out(codec);
7376 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02007377 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007378 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007379 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007380 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007381}
7382
Takashi Iwaicb53c622007-08-10 17:21:45 +02007383#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02007384static const struct hda_amp_list alc260_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02007385 { 0x07, HDA_INPUT, 0 },
7386 { 0x07, HDA_INPUT, 1 },
7387 { 0x07, HDA_INPUT, 2 },
7388 { 0x07, HDA_INPUT, 3 },
7389 { 0x07, HDA_INPUT, 4 },
7390 { } /* end */
7391};
7392#endif
7393
Kailang Yangdf694da2005-12-05 19:42:22 +01007394/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007395 * Pin config fixes
7396 */
7397enum {
7398 PINFIX_HP_DC5750,
7399};
7400
Takashi Iwaifc091762010-08-04 23:53:36 +02007401static const struct alc_fixup alc260_fixups[] = {
7402 [PINFIX_HP_DC5750] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007403 .type = ALC_FIXUP_PINS,
7404 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +02007405 { 0x11, 0x90130110 }, /* speaker */
7406 { }
7407 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007408 },
7409};
7410
Takashi Iwaia9111322011-05-02 11:30:18 +02007411static const struct snd_pci_quirk alc260_fixup_tbl[] = {
Takashi Iwaifc091762010-08-04 23:53:36 +02007412 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7413 {}
7414};
7415
7416/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007417 * ALC260 configurations
7418 */
Takashi Iwaiea734962011-01-17 11:29:34 +01007419static const char * const alc260_models[ALC260_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007420 [ALC260_BASIC] = "basic",
7421 [ALC260_HP] = "hp",
7422 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007423 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007424 [ALC260_FUJITSU_S702X] = "fujitsu",
7425 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007426 [ALC260_WILL] = "will",
7427 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007428 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007429#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007430 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007431#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007432 [ALC260_AUTO] = "auto",
7433};
7434
Takashi Iwaia9111322011-05-02 11:30:18 +02007435static const struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007436 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007437 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007438 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007439 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007440 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007441 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007442 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007443 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007444 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007445 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7446 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7447 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7448 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7449 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7450 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7451 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7452 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7453 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007454 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007455 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007456 {}
7457};
7458
Takashi Iwaia9111322011-05-02 11:30:18 +02007459static const struct alc_config_preset alc260_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007460 [ALC260_BASIC] = {
7461 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007462 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007463 .init_verbs = { alc260_init_verbs },
7464 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7465 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007466 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007467 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007468 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7469 .channel_mode = alc260_modes,
7470 .input_mux = &alc260_capture_source,
7471 },
7472 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007473 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007474 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007475 .init_verbs = { alc260_init_verbs,
7476 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007477 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7478 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007479 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7480 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007481 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7482 .channel_mode = alc260_modes,
7483 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007484 .unsol_event = alc_sku_unsol_event,
7485 .setup = alc260_hp_setup,
7486 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007487 },
Kailang Yang3f878302008-08-26 13:02:23 +02007488 [ALC260_HP_DC7600] = {
7489 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007490 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007491 .init_verbs = { alc260_init_verbs,
7492 alc260_hp_dc7600_verbs },
7493 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7494 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007495 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7496 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007497 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7498 .channel_mode = alc260_modes,
7499 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007500 .unsol_event = alc_sku_unsol_event,
7501 .setup = alc260_hp_3012_setup,
7502 .init_hook = alc_inithook,
Kailang Yang3f878302008-08-26 13:02:23 +02007503 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007504 [ALC260_HP_3013] = {
7505 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007506 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007507 .init_verbs = { alc260_hp_3013_init_verbs,
7508 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007509 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7510 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007511 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7512 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007513 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7514 .channel_mode = alc260_modes,
7515 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007516 .unsol_event = alc_sku_unsol_event,
7517 .setup = alc260_hp_3013_setup,
7518 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007519 },
7520 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007521 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007522 .init_verbs = { alc260_fujitsu_init_verbs },
7523 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7524 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007525 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7526 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007527 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7528 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007529 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7530 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007531 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007532 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007533 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007534 .init_verbs = { alc260_acer_init_verbs },
7535 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7536 .dac_nids = alc260_dac_nids,
7537 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7538 .adc_nids = alc260_dual_adc_nids,
7539 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7540 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007541 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7542 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007543 },
Michael Schwingencc959482009-02-22 18:58:45 +01007544 [ALC260_FAVORIT100] = {
7545 .mixers = { alc260_favorit100_mixer },
7546 .init_verbs = { alc260_favorit100_init_verbs },
7547 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7548 .dac_nids = alc260_dac_nids,
7549 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7550 .adc_nids = alc260_dual_adc_nids,
7551 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7552 .channel_mode = alc260_modes,
7553 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7554 .input_mux = alc260_favorit100_capture_sources,
7555 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007556 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007557 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007558 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7559 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7560 .dac_nids = alc260_dac_nids,
7561 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7562 .adc_nids = alc260_adc_nids,
7563 .dig_out_nid = ALC260_DIGOUT_NID,
7564 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7565 .channel_mode = alc260_modes,
7566 .input_mux = &alc260_capture_source,
7567 },
7568 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007569 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007570 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7571 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7572 .dac_nids = alc260_dac_nids,
7573 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7574 .adc_nids = alc260_adc_nids,
7575 .dig_out_nid = ALC260_DIGOUT_NID,
7576 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7577 .channel_mode = alc260_modes,
7578 .input_mux = &alc260_capture_source,
7579 .unsol_event = alc260_replacer_672v_unsol_event,
7580 .init_hook = alc260_replacer_672v_automute,
7581 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007582#ifdef CONFIG_SND_DEBUG
7583 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007584 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007585 .init_verbs = { alc260_test_init_verbs },
7586 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7587 .dac_nids = alc260_test_dac_nids,
7588 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7589 .adc_nids = alc260_test_adc_nids,
7590 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7591 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007592 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7593 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007594 },
7595#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007596};
7597
Linus Torvalds1da177e2005-04-16 15:20:36 -07007598static int patch_alc260(struct hda_codec *codec)
7599{
7600 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007601 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007602
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007603 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604 if (spec == NULL)
7605 return -ENOMEM;
7606
7607 codec->spec = spec;
7608
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007609 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7610 alc260_models,
7611 alc260_cfg_tbl);
7612 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007613 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007614 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007615 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007616 }
7617
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007618 if (board_config == ALC260_AUTO) {
7619 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
7620 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7621 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007622
Kailang Yangdf694da2005-12-05 19:42:22 +01007623 if (board_config == ALC260_AUTO) {
7624 /* automatic parse from the BIOS config */
7625 err = alc260_parse_auto_config(codec);
7626 if (err < 0) {
7627 alc_free(codec);
7628 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007629 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007630 printk(KERN_INFO
7631 "hda_codec: Cannot set up configuration "
7632 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007633 board_config = ALC260_BASIC;
7634 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007637 err = snd_hda_attach_beep_device(codec, 0x1);
7638 if (err < 0) {
7639 alc_free(codec);
7640 return err;
7641 }
7642
Kailang Yangdf694da2005-12-05 19:42:22 +01007643 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007644 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007645
Linus Torvalds1da177e2005-04-16 15:20:36 -07007646 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7647 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307648 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007649
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007650 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7651 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7652
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007653 if (!spec->adc_nids && spec->input_mux) {
7654 /* check whether NID 0x04 is valid */
7655 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007656 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007657 /* get type */
7658 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7659 spec->adc_nids = alc260_adc_nids_alt;
7660 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7661 } else {
7662 spec->adc_nids = alc260_adc_nids;
7663 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7664 }
7665 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007666 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007667 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007668
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007669 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaifc091762010-08-04 23:53:36 +02007670
Takashi Iwai2134ea42008-01-10 16:53:55 +01007671 spec->vmaster_nid = 0x08;
7672
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007674 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007675 spec->init_hook = alc260_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +02007676 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007677#ifdef CONFIG_SND_HDA_POWER_SAVE
7678 if (!spec->loopback.amplist)
7679 spec->loopback.amplist = alc260_loopbacks;
7680#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681
7682 return 0;
7683}
7684
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007685
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686/*
Takashi Iwai49535502009-06-30 15:28:30 +02007687 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007688 *
7689 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7690 * configuration. Each pin widget can choose any input DACs and a mixer.
7691 * Each ADC is connected from a mixer of all inputs. This makes possible
7692 * 6-channel independent captures.
7693 *
7694 * In addition, an independent DAC for the multi-playback (not used in this
7695 * driver yet).
7696 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007697#define ALC882_DIGOUT_NID 0x06
7698#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007699#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7700#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7701#define ALC1200_DIGOUT_NID 0x10
7702
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703
Takashi Iwaia9111322011-05-02 11:30:18 +02007704static const struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007705 { 8, NULL }
7706};
7707
Takashi Iwai49535502009-06-30 15:28:30 +02007708/* DACs */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007709static const hda_nid_t alc882_dac_nids[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007710 /* front, rear, clfe, rear_surr */
7711 0x02, 0x03, 0x04, 0x05
7712};
Takashi Iwai49535502009-06-30 15:28:30 +02007713#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714
Takashi Iwai49535502009-06-30 15:28:30 +02007715/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007716#define alc882_adc_nids alc880_adc_nids
7717#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007718#define alc883_adc_nids alc882_adc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007719static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7720static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
Takashi Iwai49535502009-06-30 15:28:30 +02007721#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007722
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007723static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7724static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007725#define alc883_capsrc_nids alc882_capsrc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007726static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
Takashi Iwai49535502009-06-30 15:28:30 +02007727#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007728
Linus Torvalds1da177e2005-04-16 15:20:36 -07007729/* input MUX */
7730/* FIXME: should be a matrix-type input source selection */
7731
Takashi Iwaia9111322011-05-02 11:30:18 +02007732static const struct hda_input_mux alc882_capture_source = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007733 .num_items = 4,
7734 .items = {
7735 { "Mic", 0x0 },
7736 { "Front Mic", 0x1 },
7737 { "Line", 0x2 },
7738 { "CD", 0x4 },
7739 },
7740};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007741
Takashi Iwai49535502009-06-30 15:28:30 +02007742#define alc883_capture_source alc882_capture_source
7743
Takashi Iwaia9111322011-05-02 11:30:18 +02007744static const struct hda_input_mux alc889_capture_source = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007745 .num_items = 3,
7746 .items = {
7747 { "Front Mic", 0x0 },
7748 { "Mic", 0x3 },
7749 { "Line", 0x2 },
7750 },
7751};
7752
Takashi Iwaia9111322011-05-02 11:30:18 +02007753static const struct hda_input_mux mb5_capture_source = {
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007754 .num_items = 3,
7755 .items = {
7756 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307757 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007758 { "CD", 0x4 },
7759 },
7760};
7761
Takashi Iwaia9111322011-05-02 11:30:18 +02007762static const struct hda_input_mux macmini3_capture_source = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007763 .num_items = 2,
7764 .items = {
7765 { "Line", 0x2 },
7766 { "CD", 0x4 },
7767 },
7768};
7769
Takashi Iwaia9111322011-05-02 11:30:18 +02007770static const struct hda_input_mux alc883_3stack_6ch_intel = {
Takashi Iwai49535502009-06-30 15:28:30 +02007771 .num_items = 4,
7772 .items = {
7773 { "Mic", 0x1 },
7774 { "Front Mic", 0x0 },
7775 { "Line", 0x2 },
7776 { "CD", 0x4 },
7777 },
7778};
7779
Takashi Iwaia9111322011-05-02 11:30:18 +02007780static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007781 .num_items = 2,
7782 .items = {
7783 { "Mic", 0x1 },
7784 { "Line", 0x2 },
7785 },
7786};
7787
Takashi Iwaia9111322011-05-02 11:30:18 +02007788static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007789 .num_items = 4,
7790 .items = {
7791 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007792 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007793 { "Line", 0x2 },
7794 { "CD", 0x4 },
7795 },
7796};
7797
Takashi Iwaia9111322011-05-02 11:30:18 +02007798static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007799 .num_items = 2,
7800 .items = {
7801 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007802 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007803 },
7804};
7805
Takashi Iwaia9111322011-05-02 11:30:18 +02007806static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007807 .num_items = 3,
7808 .items = {
7809 { "Mic", 0x0 },
7810 { "Front Mic", 0x1 },
7811 { "Line", 0x4 },
7812 },
7813};
7814
Takashi Iwaia9111322011-05-02 11:30:18 +02007815static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007816 .num_items = 2,
7817 .items = {
7818 { "Mic", 0x0 },
7819 { "Line", 0x2 },
7820 },
7821};
7822
Takashi Iwaia9111322011-05-02 11:30:18 +02007823static const struct hda_input_mux alc889A_mb31_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007824 .num_items = 2,
7825 .items = {
7826 { "Mic", 0x0 },
7827 /* Front Mic (0x01) unused */
7828 { "Line", 0x2 },
7829 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007830 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007831 },
7832};
7833
Takashi Iwaia9111322011-05-02 11:30:18 +02007834static const struct hda_input_mux alc889A_imac91_capture_source = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007835 .num_items = 2,
7836 .items = {
7837 { "Mic", 0x01 },
7838 { "Line", 0x2 }, /* Not sure! */
7839 },
7840};
7841
Takashi Iwai49535502009-06-30 15:28:30 +02007842/*
7843 * 2ch mode
7844 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007845static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007846 { 2, NULL }
7847};
7848
Kailang Yangdf694da2005-12-05 19:42:22 +01007849/*
Kailang Yang272a5272007-05-14 11:00:38 +02007850 * 2ch mode
7851 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007852static const struct hda_verb alc882_3ST_ch2_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007853 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7854 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7855 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7856 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7857 { } /* end */
7858};
7859
7860/*
Takashi Iwai49535502009-06-30 15:28:30 +02007861 * 4ch mode
7862 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007863static const struct hda_verb alc882_3ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007864 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7865 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7866 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7867 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7868 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7869 { } /* end */
7870};
7871
7872/*
Kailang Yang272a5272007-05-14 11:00:38 +02007873 * 6ch mode
7874 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007875static const struct hda_verb alc882_3ST_ch6_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007876 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7877 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7878 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7879 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7880 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7881 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7882 { } /* end */
7883};
7884
Takashi Iwaia9111322011-05-02 11:30:18 +02007885static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007886 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007887 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007888 { 6, alc882_3ST_ch6_init },
7889};
7890
Takashi Iwai49535502009-06-30 15:28:30 +02007891#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7892
Kailang Yang272a5272007-05-14 11:00:38 +02007893/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307894 * 2ch mode
7895 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007896static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307897 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7898 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7899 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7900 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7901 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7902 { } /* end */
7903};
7904
7905/*
7906 * 4ch mode
7907 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007908static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307909 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7910 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7911 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7912 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7913 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7914 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7915 { } /* end */
7916};
7917
7918/*
7919 * 6ch mode
7920 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007921static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307922 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7923 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7924 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7925 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7926 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7927 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7928 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7929 { } /* end */
7930};
7931
Takashi Iwaia9111322011-05-02 11:30:18 +02007932static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307933 { 2, alc883_3ST_ch2_clevo_init },
7934 { 4, alc883_3ST_ch4_clevo_init },
7935 { 6, alc883_3ST_ch6_clevo_init },
7936};
7937
7938
7939/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007940 * 6ch mode
7941 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007942static const struct hda_verb alc882_sixstack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007943 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7944 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7945 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7946 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7947 { } /* end */
7948};
7949
7950/*
7951 * 8ch mode
7952 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007953static const struct hda_verb alc882_sixstack_ch8_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007954 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7955 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7956 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7957 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7958 { } /* end */
7959};
7960
Takashi Iwaia9111322011-05-02 11:30:18 +02007961static const struct hda_channel_mode alc882_sixstack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007962 { 6, alc882_sixstack_ch6_init },
7963 { 8, alc882_sixstack_ch8_init },
7964};
7965
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007966
7967/* Macbook Air 2,1 */
7968
Takashi Iwaia9111322011-05-02 11:30:18 +02007969static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007970 { 2, NULL },
7971};
7972
Takashi Iwai87350ad2007-08-16 18:19:38 +02007973/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007974 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007975 */
7976
7977/*
7978 * 2ch mode
7979 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007980static const struct hda_verb alc885_mbp_ch2_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007981 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7982 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7983 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7984 { } /* end */
7985};
7986
7987/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007988 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007989 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007990static const struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007991 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7992 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7993 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7994 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7995 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7996 { } /* end */
7997};
7998
Takashi Iwaia9111322011-05-02 11:30:18 +02007999static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02008000 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008001 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02008002};
8003
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008004/*
8005 * 2ch
8006 * Speakers/Woofer/HP = Front
8007 * LineIn = Input
8008 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008009static const struct hda_verb alc885_mb5_ch2_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008010 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8011 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8012 { } /* end */
8013};
8014
8015/*
8016 * 6ch mode
8017 * Speakers/HP = Front
8018 * Woofer = LFE
8019 * LineIn = Surround
8020 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008021static const struct hda_verb alc885_mb5_ch6_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008022 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8023 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8024 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
8025 { } /* end */
8026};
8027
Takashi Iwaia9111322011-05-02 11:30:18 +02008028static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008029 { 2, alc885_mb5_ch2_init },
8030 { 6, alc885_mb5_ch6_init },
8031};
Takashi Iwai87350ad2007-08-16 18:19:38 +02008032
Takashi Iwaid01aecd2010-02-23 08:07:15 +01008033#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02008034
8035/*
8036 * 2ch mode
8037 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008038static const struct hda_verb alc883_4ST_ch2_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008039 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8040 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8041 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8042 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8043 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8044 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8045 { } /* end */
8046};
8047
8048/*
8049 * 4ch mode
8050 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008051static const struct hda_verb alc883_4ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008052 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8053 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8054 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8055 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8056 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8057 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8058 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8059 { } /* end */
8060};
8061
8062/*
8063 * 6ch mode
8064 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008065static const struct hda_verb alc883_4ST_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008066 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8067 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8068 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8069 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8070 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
8071 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8072 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8073 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8074 { } /* end */
8075};
8076
8077/*
8078 * 8ch mode
8079 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008080static const struct hda_verb alc883_4ST_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008081 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8082 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8083 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
8084 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8085 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8086 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
8087 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8088 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8089 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8090 { } /* end */
8091};
8092
Takashi Iwaia9111322011-05-02 11:30:18 +02008093static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008094 { 2, alc883_4ST_ch2_init },
8095 { 4, alc883_4ST_ch4_init },
8096 { 6, alc883_4ST_ch6_init },
8097 { 8, alc883_4ST_ch8_init },
8098};
8099
8100
8101/*
8102 * 2ch mode
8103 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008104static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008105 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8106 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8107 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8108 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8109 { } /* end */
8110};
8111
8112/*
8113 * 4ch mode
8114 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008115static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008116 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
8117 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8118 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8119 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8120 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8121 { } /* end */
8122};
8123
8124/*
8125 * 6ch mode
8126 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008127static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008128 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8129 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8130 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
8131 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8132 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
8133 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
8134 { } /* end */
8135};
8136
Takashi Iwaia9111322011-05-02 11:30:18 +02008137static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008138 { 2, alc883_3ST_ch2_intel_init },
8139 { 4, alc883_3ST_ch4_intel_init },
8140 { 6, alc883_3ST_ch6_intel_init },
8141};
8142
8143/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008144 * 2ch mode
8145 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008146static const struct hda_verb alc889_ch2_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008147 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
8148 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
8149 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
8150 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
8151 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
8152 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8153 { } /* end */
8154};
8155
8156/*
Takashi Iwai49535502009-06-30 15:28:30 +02008157 * 6ch mode
8158 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008159static const struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008160 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
8161 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
8162 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
8163 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
8164 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008165 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
8166 { } /* end */
8167};
8168
8169/*
8170 * 8ch mode
8171 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008172static const struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008173 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
8174 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
8175 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
8176 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
8177 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008178 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8179 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008180 { } /* end */
8181};
8182
Takashi Iwaia9111322011-05-02 11:30:18 +02008183static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008184 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008185 { 6, alc889_ch6_intel_init },
8186 { 8, alc889_ch8_intel_init },
8187};
8188
8189/*
8190 * 6ch mode
8191 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008192static const struct hda_verb alc883_sixstack_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008193 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
8194 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8195 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8196 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8197 { } /* end */
8198};
8199
8200/*
8201 * 8ch mode
8202 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008203static const struct hda_verb alc883_sixstack_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008204 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8205 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8206 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8207 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8208 { } /* end */
8209};
8210
Takashi Iwaia9111322011-05-02 11:30:18 +02008211static const struct hda_channel_mode alc883_sixstack_modes[2] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008212 { 6, alc883_sixstack_ch6_init },
8213 { 8, alc883_sixstack_ch8_init },
8214};
8215
8216
Linus Torvalds1da177e2005-04-16 15:20:36 -07008217/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
8218 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
8219 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008220static const struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02008221 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008222 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008223 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008224 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008225 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8226 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008227 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8228 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008229 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008230 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008231 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8232 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8233 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8234 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8235 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8236 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008237 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008238 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8239 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008240 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008242 { } /* end */
8243};
8244
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008245/* Macbook Air 2,1 same control for HP and internal Speaker */
8246
Takashi Iwaia9111322011-05-02 11:30:18 +02008247static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008248 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8249 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
8250 { }
8251};
8252
8253
Takashi Iwaia9111322011-05-02 11:30:18 +02008254static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008255 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8256 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
8257 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8258 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
8259 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01008260 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8261 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008262 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8263 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008264 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
8265 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008266 { } /* end */
8267};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008268
Takashi Iwaia9111322011-05-02 11:30:18 +02008269static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008270 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8271 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8272 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8273 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8274 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8275 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10308276 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8277 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09308278 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8279 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008280 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8281 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008282 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
8283 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008284 { } /* end */
8285};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008286
Takashi Iwaia9111322011-05-02 11:30:18 +02008287static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008288 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8289 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8290 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8291 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8292 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8293 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
8294 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8295 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
8296 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8297 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008298 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008299 { } /* end */
8300};
8301
Takashi Iwaia9111322011-05-02 11:30:18 +02008302static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008303 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8304 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008305 { } /* end */
8306};
8307
8308
Takashi Iwaia9111322011-05-02 11:30:18 +02008309static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02008310 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8311 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8312 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8313 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8314 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8315 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8316 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008317 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008318 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008319 { } /* end */
8320};
8321
Takashi Iwaia9111322011-05-02 11:30:18 +02008322static const struct snd_kcontrol_new alc882_targa_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008323 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8324 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8325 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8326 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8327 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8328 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8329 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8330 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8331 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008332 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008333 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8334 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008335 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008336 { } /* end */
8337};
8338
8339/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8340 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8341 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008342static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008343 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8344 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8345 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8346 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8347 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8348 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8349 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8350 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8351 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8352 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8353 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8354 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008355 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008356 { } /* end */
8357};
8358
Takashi Iwaia9111322011-05-02 11:30:18 +02008359static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008360 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8361 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8362 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8363 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8364 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8365 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8366 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8367 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008368 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008369 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008370 { } /* end */
8371};
8372
Takashi Iwaia9111322011-05-02 11:30:18 +02008373static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008374 {
8375 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8376 .name = "Channel Mode",
8377 .info = alc_ch_mode_info,
8378 .get = alc_ch_mode_get,
8379 .put = alc_ch_mode_put,
8380 },
8381 { } /* end */
8382};
8383
Takashi Iwaia9111322011-05-02 11:30:18 +02008384static const struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008385 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008386 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8387 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008388 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008389 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8390 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008391 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008392 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8393 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008394 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008395 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8396 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008397
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008398 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008399 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008400 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008401 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008402 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008403 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008404 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008405 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008406 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008407 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008408 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008410 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008411 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008412 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008413 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008414 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008415 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008416 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8417 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008418 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008419 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8420 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008421 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008422 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8423 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8424 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8425 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8426 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008427 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008428 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008429
8430 /* FIXME: use matrix-type input source selection */
8431 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008432 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008433 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008434 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008435 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008436 /* ADC2: mute amp left and right */
8437 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008438 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008439 /* ADC3: mute amp left and right */
8440 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008441 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442
8443 { }
8444};
8445
Takashi Iwaia9111322011-05-02 11:30:18 +02008446static const struct hda_verb alc882_adc1_init_verbs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008447 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8448 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8449 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8450 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8451 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8452 /* ADC1: mute amp left and right */
8453 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8454 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8455 { }
8456};
8457
Takashi Iwaia9111322011-05-02 11:30:18 +02008458static const struct hda_verb alc882_eapd_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008459 /* change to EAPD mode */
8460 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008461 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008462 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008463};
8464
Takashi Iwaia9111322011-05-02 11:30:18 +02008465static const struct hda_verb alc889_eapd_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008466 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8467 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8468 { }
8469};
8470
Takashi Iwaia9111322011-05-02 11:30:18 +02008471static const struct hda_verb alc_hp15_unsol_verbs[] = {
Wu Fengguang6732bd02009-07-30 09:19:14 +02008472 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8473 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8474 {}
8475};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008476
Takashi Iwaia9111322011-05-02 11:30:18 +02008477static const struct hda_verb alc885_init_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008478 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008479 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8480 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008481 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008482 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8483 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008484 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008485 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8486 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008487 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008488 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8489 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008490
8491 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008492 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008493 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8494 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8495 /* Front Pin: output 0 (0x0c) */
8496 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8497 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8498 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8499 /* Rear Pin: output 1 (0x0d) */
8500 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8501 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8502 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8503 /* CLFE Pin: output 2 (0x0e) */
8504 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8505 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8506 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8507 /* Side Pin: output 3 (0x0f) */
8508 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8509 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8510 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8511 /* Mic (rear) pin: input vref at 80% */
8512 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8513 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8514 /* Front Mic pin: input vref at 80% */
8515 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8516 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8517 /* Line In pin: input */
8518 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8519 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8520
8521 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8522 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008523 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008524 /* Input mixer2 */
8525 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008526 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008527 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008528 /* ADC2: mute amp left and right */
8529 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8530 /* ADC3: mute amp left and right */
8531 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8532
8533 { }
8534};
8535
Takashi Iwaia9111322011-05-02 11:30:18 +02008536static const struct hda_verb alc885_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008537 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8538 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8539 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8540 { }
8541};
8542
8543
8544/* Unmute Selector 24h and set the default input to front mic */
Takashi Iwaia9111322011-05-02 11:30:18 +02008545static const struct hda_verb alc889_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008546 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8547 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8548 { }
8549};
8550
8551
Takashi Iwai49535502009-06-30 15:28:30 +02008552#define alc883_init_verbs alc882_base_init_verbs
8553
Tobin Davis9102cd12006-12-15 10:02:12 +01008554/* Mac Pro test */
Takashi Iwaia9111322011-05-02 11:30:18 +02008555static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008556 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8557 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8558 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8559 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8560 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008561 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008562 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8563 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008564 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008565 { } /* end */
8566};
8567
Takashi Iwaia9111322011-05-02 11:30:18 +02008568static const struct hda_verb alc882_macpro_init_verbs[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008569 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8570 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8571 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8572 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8573 /* Front Pin: output 0 (0x0c) */
8574 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8575 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8576 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8577 /* Front Mic pin: input vref at 80% */
8578 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8579 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8580 /* Speaker: output */
8581 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8582 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8583 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8584 /* Headphone output (output 0 - 0x0c) */
8585 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8586 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8587 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8588
8589 /* FIXME: use matrix-type input source selection */
8590 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8591 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8592 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8593 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8594 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8595 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8596 /* Input mixer2 */
8597 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8598 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8599 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8600 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8601 /* Input mixer3 */
8602 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8603 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8604 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8605 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8606 /* ADC1: mute amp left and right */
8607 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8608 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8609 /* ADC2: mute amp left and right */
8610 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8611 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8612 /* ADC3: mute amp left and right */
8613 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8614 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8615
8616 { }
8617};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008618
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008619/* Macbook 5,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008620static const struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008621 /* DACs */
8622 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8623 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8624 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8625 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008626 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008627 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8628 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8629 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008630 /* Surround mixer */
8631 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8632 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8633 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8634 /* LFE mixer */
8635 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8636 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8637 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8638 /* HP mixer */
8639 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8640 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8641 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8642 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008643 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8644 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008645 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8646 /* LFE Pin (0x0e) */
8647 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8648 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8649 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8650 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008651 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8652 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008653 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308654 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008655 /* Front Mic pin: input vref at 80% */
8656 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8657 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8658 /* Line In pin */
8659 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8660 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8661
Alex Murrayb8f171e2010-06-14 12:08:43 +09308662 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8663 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8664 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008665 { }
8666};
8667
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008668/* Macmini 3,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008669static const struct hda_verb alc885_macmini3_init_verbs[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008670 /* DACs */
8671 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8672 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8673 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8674 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8675 /* Front mixer */
8676 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8677 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8678 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8679 /* Surround mixer */
8680 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8681 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8682 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8683 /* LFE mixer */
8684 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8685 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8686 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8687 /* HP mixer */
8688 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8689 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8690 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8691 /* Front Pin (0x0c) */
8692 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8693 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8694 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8695 /* LFE Pin (0x0e) */
8696 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8697 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8698 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8699 /* HP Pin (0x0f) */
8700 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8701 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8702 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8703 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8704 /* Line In pin */
8705 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8706 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8707
8708 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8709 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8710 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8711 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8712 { }
8713};
8714
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008715
Takashi Iwaia9111322011-05-02 11:30:18 +02008716static const struct hda_verb alc885_mba21_init_verbs[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008717 /*Internal and HP Speaker Mixer*/
8718 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8719 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8720 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8721 /*Internal Speaker Pin (0x0c)*/
8722 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8723 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8724 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8725 /* HP Pin: output 0 (0x0e) */
8726 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8727 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8728 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8729 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8730 /* Line in (is hp when jack connected)*/
8731 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8732 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8733
8734 { }
8735 };
8736
8737
Takashi Iwai87350ad2007-08-16 18:19:38 +02008738/* Macbook Pro rev3 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008739static const struct hda_verb alc885_mbp3_init_verbs[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02008740 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8741 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8742 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8743 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8744 /* Rear mixer */
8745 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8746 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8747 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008748 /* HP mixer */
8749 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8750 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8751 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008752 /* Front Pin: output 0 (0x0c) */
8753 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8754 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8755 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008756 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008757 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008758 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8759 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008760 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8761 /* Mic (rear) pin: input vref at 80% */
8762 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8763 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8764 /* Front Mic pin: input vref at 80% */
8765 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8766 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8767 /* Line In pin: use output 1 when in LineOut mode */
8768 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8769 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8770 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8771
8772 /* FIXME: use matrix-type input source selection */
8773 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8774 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8775 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8776 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8777 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8778 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8779 /* Input mixer2 */
8780 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8781 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8782 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8783 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8784 /* Input mixer3 */
8785 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8786 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8787 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8788 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8789 /* ADC1: mute amp left and right */
8790 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8791 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8792 /* ADC2: mute amp left and right */
8793 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8794 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8795 /* ADC3: mute amp left and right */
8796 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8797 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8798
8799 { }
8800};
8801
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008802/* iMac 9,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008803static const struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008804 /* Internal Speaker Pin (0x0c) */
8805 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8806 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8807 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8808 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8809 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8810 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8811 /* HP Pin: Rear */
8812 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8813 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8814 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8815 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8816 /* Line in Rear */
8817 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8818 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8819 /* Front Mic pin: input vref at 80% */
8820 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8821 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008822 /* Rear mixer */
8823 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8824 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8825 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008826 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8827 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8828 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8829 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8830 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008831 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8832 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8833 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8834 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008835 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008836 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8837 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8838 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8839 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008840 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008841 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8842 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8843 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8844 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008845 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008846 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8847 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008848 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008849 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8850 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008851 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008852 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8853 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008854 { }
8855};
8856
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008857/* iMac 24 mixer. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008858static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008859 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8860 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8861 { } /* end */
8862};
8863
8864/* iMac 24 init verbs. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008865static const struct hda_verb alc885_imac24_init_verbs[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008866 /* Internal speakers: output 0 (0x0c) */
8867 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8868 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8869 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8870 /* Internal speakers: output 0 (0x0c) */
8871 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8872 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8873 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8874 /* Headphone: output 0 (0x0c) */
8875 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8876 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8877 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8878 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8879 /* Front Mic: input vref at 80% */
8880 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8881 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8882 { }
8883};
8884
8885/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008886static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008887{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008888 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008889
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008890 spec->autocfg.hp_pins[0] = 0x14;
8891 spec->autocfg.speaker_pins[0] = 0x18;
8892 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008893 spec->automute = 1;
8894 spec->automute_mode = ALC_AUTOMUTE_AMP;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008895}
8896
Takashi Iwai9d54f082010-02-22 08:34:40 +01008897#define alc885_mb5_setup alc885_imac24_setup
8898#define alc885_macmini3_setup alc885_imac24_setup
8899
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008900/* Macbook Air 2,1 */
8901static void alc885_mba21_setup(struct hda_codec *codec)
8902{
8903 struct alc_spec *spec = codec->spec;
8904
8905 spec->autocfg.hp_pins[0] = 0x14;
8906 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02008907 spec->automute = 1;
8908 spec->automute_mode = ALC_AUTOMUTE_AMP;
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008909}
8910
8911
8912
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008913static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008914{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008915 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008916
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008917 spec->autocfg.hp_pins[0] = 0x15;
8918 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02008919 spec->automute = 1;
8920 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008921}
8922
Takashi Iwai9d54f082010-02-22 08:34:40 +01008923static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308924{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008925 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308926
Takashi Iwai9d54f082010-02-22 08:34:40 +01008927 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008928 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008929 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008930 spec->automute = 1;
8931 spec->automute_mode = ALC_AUTOMUTE_AMP;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008932}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008933
Takashi Iwaia9111322011-05-02 11:30:18 +02008934static const struct hda_verb alc882_targa_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008935 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8936 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8937
8938 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8939 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008940
Kailang Yang272a5272007-05-14 11:00:38 +02008941 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8942 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8943 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8944
8945 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008946 { } /* end */
8947};
8948
8949/* toggle speaker-output according to the hp-jack state */
8950static void alc882_targa_automute(struct hda_codec *codec)
8951{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008952 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02008953 alc_hp_automute(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008954 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008955 spec->jack_present ? 1 : 3);
8956}
8957
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008958static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008959{
8960 struct alc_spec *spec = codec->spec;
8961
8962 spec->autocfg.hp_pins[0] = 0x14;
8963 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02008964 spec->automute = 1;
8965 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02008966}
8967
8968static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8969{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008970 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008971 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008972}
8973
Takashi Iwaia9111322011-05-02 11:30:18 +02008974static const struct hda_verb alc882_asus_a7j_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008975 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8976 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8977
8978 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8979 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8980 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008981
Kailang Yang272a5272007-05-14 11:00:38 +02008982 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8983 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8984 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8985
8986 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8987 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8988 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8989 { } /* end */
8990};
8991
Takashi Iwaia9111322011-05-02 11:30:18 +02008992static const struct hda_verb alc882_asus_a7m_verbs[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008993 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8994 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8995
8996 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8997 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8998 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008999
Takashi Iwai914759b2007-09-06 14:52:04 +02009000 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
9001 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
9002 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
9003
9004 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
9005 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
9006 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
9007 { } /* end */
9008};
9009
Tobin Davis9102cd12006-12-15 10:02:12 +01009010static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
9011{
9012 unsigned int gpiostate, gpiomask, gpiodir;
9013
9014 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
9015 AC_VERB_GET_GPIO_DATA, 0);
9016
9017 if (!muted)
9018 gpiostate |= (1 << pin);
9019 else
9020 gpiostate &= ~(1 << pin);
9021
9022 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
9023 AC_VERB_GET_GPIO_MASK, 0);
9024 gpiomask |= (1 << pin);
9025
9026 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
9027 AC_VERB_GET_GPIO_DIRECTION, 0);
9028 gpiodir |= (1 << pin);
9029
9030
9031 snd_hda_codec_write(codec, codec->afg, 0,
9032 AC_VERB_SET_GPIO_MASK, gpiomask);
9033 snd_hda_codec_write(codec, codec->afg, 0,
9034 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
9035
9036 msleep(1);
9037
9038 snd_hda_codec_write(codec, codec->afg, 0,
9039 AC_VERB_SET_GPIO_DATA, gpiostate);
9040}
9041
Takashi Iwai7debbe52007-08-16 15:01:03 +02009042/* set up GPIO at initialization */
9043static void alc885_macpro_init_hook(struct hda_codec *codec)
9044{
9045 alc882_gpio_mute(codec, 0, 0);
9046 alc882_gpio_mute(codec, 1, 0);
9047}
9048
9049/* set up GPIO and update auto-muting at initialization */
9050static void alc885_imac24_init_hook(struct hda_codec *codec)
9051{
9052 alc885_macpro_init_hook(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02009053 alc_hp_automute(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02009054}
9055
Kailang Yangdf694da2005-12-05 19:42:22 +01009056/*
9057 * generic initialization of ADC, input mixers and output mixers
9058 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009059static const struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01009060 /*
9061 * Unmute ADC0-2 and set the default input to mic-in
9062 */
Kailang Yangdf694da2005-12-05 19:42:22 +01009063 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
9064 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9065 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
9066 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9067
Kailang Yangdf694da2005-12-05 19:42:22 +01009068 /*
9069 * Set up output mixers (0x0c - 0x0f)
9070 */
9071 /* set vol=0 to output mixers */
9072 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9073 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9074 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9075 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
9076 /* set up input amps for analog loopback */
9077 /* Amp Indices: DAC = 0, mixer = 1 */
9078 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9079 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9080 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9081 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9082 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9083 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9084 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9085 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9086 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9087 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9088
9089 /* FIXME: use matrix-type input source selection */
9090 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01009091 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01009092 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009093 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01009094 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01009095 { }
9096};
9097
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009098/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009099static const struct hda_verb alc889A_mb31_ch2_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009100 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
9101 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
9102 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
9103 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
9104 { } /* end */
9105};
9106
9107/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009108static const struct hda_verb alc889A_mb31_ch4_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009109 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
9110 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
9111 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
9112 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
9113 { } /* end */
9114};
9115
9116/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009117static const struct hda_verb alc889A_mb31_ch5_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009118 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
9119 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
9120 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
9121 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
9122 { } /* end */
9123};
9124
9125/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02009126static const struct hda_verb alc889A_mb31_ch6_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009127 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
9128 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
9129 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
9130 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
9131 { } /* end */
9132};
9133
Takashi Iwaia9111322011-05-02 11:30:18 +02009134static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009135 { 2, alc889A_mb31_ch2_init },
9136 { 4, alc889A_mb31_ch4_init },
9137 { 5, alc889A_mb31_ch5_init },
9138 { 6, alc889A_mb31_ch6_init },
9139};
9140
Takashi Iwaia9111322011-05-02 11:30:18 +02009141static const struct hda_verb alc883_medion_eapd_verbs[] = {
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01009142 /* eanable EAPD on medion laptop */
9143 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9144 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
9145 { }
9146};
9147
Takashi Iwai49535502009-06-30 15:28:30 +02009148#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009149
Takashi Iwaia9111322011-05-02 11:30:18 +02009150static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009151 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9152 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9153 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9154 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9155 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9156 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9157 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9158 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009159 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009160 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9161 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009162 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009163 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009164 { } /* end */
9165};
9166
Takashi Iwaia9111322011-05-02 11:30:18 +02009167static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009168 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9169 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
9170 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9171 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, 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),
Jiang zhe368c7a92008-03-04 11:20:33 +01009174 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009175 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009176 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009177 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01009178 { } /* end */
9179};
9180
Takashi Iwaia9111322011-05-02 11:30:18 +02009181static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01009182 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9183 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
9184 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9185 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
9186 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009187 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01009188 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009189 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009190 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009191 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01009192 { } /* end */
9193};
9194
Takashi Iwaia9111322011-05-02 11:30:18 +02009195static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009196 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9197 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9199 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9200 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9201 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9202 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9203 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009204 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009205 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9206 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009207 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009208 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009209 { } /* end */
9210};
9211
Takashi Iwaia9111322011-05-02 11:30:18 +02009212static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009213 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9214 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9215 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9216 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9217 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9218 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9219 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9220 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9221 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9222 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9223 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, 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 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009227 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009228 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9229 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009230 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009231 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009232 { } /* end */
9233};
9234
Takashi Iwaia9111322011-05-02 11:30:18 +02009235static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
Jiang zhe17bba1b2008-06-04 12:11:07 +02009236 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9237 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9238 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9239 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9240 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9241 HDA_OUTPUT),
9242 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9243 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9244 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9245 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9246 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9247 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9248 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9249 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9250 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009251 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009252 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9253 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009254 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009255 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009256 { } /* end */
9257};
9258
Takashi Iwaia9111322011-05-02 11:30:18 +02009259static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009260 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9261 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9262 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9263 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9264 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9265 HDA_OUTPUT),
9266 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9267 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9268 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9269 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9270 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
9271 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9272 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9273 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9274 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009275 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009276 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
9277 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009278 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009279 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9280 { } /* end */
9281};
9282
Takashi Iwaia9111322011-05-02 11:30:18 +02009283static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02009284 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009285 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009286 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009287 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009288 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9289 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009290 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9291 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009292 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9293 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9294 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9295 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9296 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9297 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009298 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009299 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9300 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009301 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009302 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009303 { } /* end */
9304};
9305
Takashi Iwaia9111322011-05-02 11:30:18 +02009306static const struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009307 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009308 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009309 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009310 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009311 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9312 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9313 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9314 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9315 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9316 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9317 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9318 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9319 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9320 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9321 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009322 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009323 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009324 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009325};
Kailang Yangccc656c2006-10-17 12:32:26 +02009326
Takashi Iwaia9111322011-05-02 11:30:18 +02009327static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009328 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009329 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009330 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009331 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009332 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9333 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9334 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009335 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009336 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009337 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009338 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009339 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009340 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009341};
Kailang Yangccc656c2006-10-17 12:32:26 +02009342
Takashi Iwaia9111322011-05-02 11:30:18 +02009343static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009344 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9345 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009346 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009347 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009348 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009349 { } /* end */
9350};
9351
Takashi Iwaia9111322011-05-02 11:30:18 +02009352static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009353 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9354 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009355 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9356 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009357 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9358 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009359 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009360 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009361 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009362};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009363
Takashi Iwaia9111322011-05-02 11:30:18 +02009364static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009365 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9366 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9367 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9368 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9369 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9370 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9371 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009372 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9373 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009374 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02009375};
Kailang Yang272a5272007-05-14 11:00:38 +02009376
Takashi Iwaia9111322011-05-02 11:30:18 +02009377static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009378 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9379 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9380 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9381 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9382 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9383 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9384 { } /* end */
9385};
9386
Takashi Iwaia9111322011-05-02 11:30:18 +02009387static const struct hda_verb alc883_medion_wim2160_verbs[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009388 /* Unmute front mixer */
9389 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9390 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9391
9392 /* Set speaker pin to front mixer */
9393 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9394
9395 /* Init headphone pin */
9396 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9397 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9398 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9399 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9400
9401 { } /* end */
9402};
9403
9404/* toggle speaker-output according to the hp-jack state */
9405static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9406{
9407 struct alc_spec *spec = codec->spec;
9408
9409 spec->autocfg.hp_pins[0] = 0x1a;
9410 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009411 spec->automute = 1;
9412 spec->automute_mode = ALC_AUTOMUTE_AMP;
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009413}
9414
Takashi Iwaia9111322011-05-02 11:30:18 +02009415static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009416 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9417 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009418 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009419 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9420 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009421 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009422 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009423 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009424 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009425};
Tobin Davis2880a862007-08-07 11:50:26 +02009426
Takashi Iwaia9111322011-05-02 11:30:18 +02009427static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01009428 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009429 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009430 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9431 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009432 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9433 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9434 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009435 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009436 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9437 { } /* end */
9438};
9439
Takashi Iwaia9111322011-05-02 11:30:18 +02009440static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009441 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9442 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9443 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9444 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9445 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9446 0x0d, 1, 0x0, HDA_OUTPUT),
9447 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9448 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9449 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9450 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9451 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009452 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9453 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9454 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9455 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9456 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009457 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009458 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9459 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009460 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009461 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009462 { } /* end */
9463};
9464
Takashi Iwaia9111322011-05-02 11:30:18 +02009465static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009466 /* Output mixers */
9467 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9468 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9469 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9470 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9471 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9472 HDA_OUTPUT),
9473 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9474 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9475 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9476 /* Output switches */
9477 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9478 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9479 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9480 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009481 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9482 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009483 /* Input mixers */
9484 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9485 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9486 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9487 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9488 { } /* end */
9489};
9490
Takashi Iwaia9111322011-05-02 11:30:18 +02009491static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009492 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9493 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9494 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9495 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009496 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c2009-06-05 00:47:26 +02009497 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9498 { } /* end */
9499};
9500
Takashi Iwaia9111322011-05-02 11:30:18 +02009501static const struct hda_bind_ctls alc883_bind_cap_vol = {
Kailang Yange2757d52008-08-26 13:17:46 +02009502 .ops = &snd_hda_bind_vol,
9503 .values = {
9504 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9505 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9506 0
9507 },
9508};
9509
Takashi Iwaia9111322011-05-02 11:30:18 +02009510static const struct hda_bind_ctls alc883_bind_cap_switch = {
Kailang Yange2757d52008-08-26 13:17:46 +02009511 .ops = &snd_hda_bind_sw,
9512 .values = {
9513 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9514 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9515 0
9516 },
9517};
9518
Takashi Iwaia9111322011-05-02 11:30:18 +02009519static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009520 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9521 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9522 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9523 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9524 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9525 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009526 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009527 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009528 { } /* end */
9529};
9530
Takashi Iwaia9111322011-05-02 11:30:18 +02009531static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009532 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9533 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9534 {
9535 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9536 /* .name = "Capture Source", */
9537 .name = "Input Source",
9538 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009539 .info = alc_mux_enum_info,
9540 .get = alc_mux_enum_get,
9541 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009542 },
9543 { } /* end */
9544};
9545
Takashi Iwaia9111322011-05-02 11:30:18 +02009546static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009547 {
9548 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9549 .name = "Channel Mode",
9550 .info = alc_ch_mode_info,
9551 .get = alc_ch_mode_get,
9552 .put = alc_ch_mode_put,
9553 },
9554 { } /* end */
9555};
9556
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009557/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009558static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009559{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009560 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009561
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009562 spec->autocfg.hp_pins[0] = 0x15;
9563 spec->autocfg.speaker_pins[0] = 0x14;
9564 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009565 spec->automute = 1;
9566 spec->automute_mode = ALC_AUTOMUTE_AMP;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009567}
9568
Takashi Iwaia9111322011-05-02 11:30:18 +02009569static const struct hda_verb alc883_mitac_verbs[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009570 /* HP */
9571 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9572 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9573 /* Subwoofer */
9574 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9575 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9576
9577 /* enable unsolicited event */
9578 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9579 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9580
9581 { } /* end */
9582};
9583
Takashi Iwaia9111322011-05-02 11:30:18 +02009584static const struct hda_verb alc883_clevo_m540r_verbs[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309585 /* HP */
9586 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9587 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9588 /* Int speaker */
9589 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9590
9591 /* enable unsolicited event */
9592 /*
9593 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9594 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9595 */
9596
9597 { } /* end */
9598};
9599
Takashi Iwaia9111322011-05-02 11:30:18 +02009600static const struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009601 /* HP */
9602 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9603 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9604 /* Int speaker */
9605 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9606 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9607
9608 /* enable unsolicited event */
9609 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009610 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009611
9612 { } /* end */
9613};
9614
Takashi Iwaia9111322011-05-02 11:30:18 +02009615static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01009616 /* HP */
9617 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9618 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9619 /* Subwoofer */
9620 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9621 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9622
9623 /* enable unsolicited event */
9624 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9625
9626 { } /* end */
9627};
9628
Takashi Iwaia9111322011-05-02 11:30:18 +02009629static const struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009630 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9631 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9632
9633 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9634 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009635
David Heidelberger64a8be72009-06-08 16:15:18 +02009636/* Connect Line-Out side jack (SPDIF) to Side */
9637 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9638 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9639 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9640/* Connect Mic jack to CLFE */
9641 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9642 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9643 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9644/* Connect Line-in jack to Surround */
9645 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9646 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9647 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9648/* Connect HP out jack to Front */
9649 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9650 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9651 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009652
9653 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009654
9655 { } /* end */
9656};
9657
Takashi Iwaia9111322011-05-02 11:30:18 +02009658static const struct hda_verb alc883_lenovo_101e_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009659 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9660 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9661 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9662 { } /* end */
9663};
9664
Takashi Iwaia9111322011-05-02 11:30:18 +02009665static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009666 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9667 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9668 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9669 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9670 { } /* end */
9671};
9672
Takashi Iwaia9111322011-05-02 11:30:18 +02009673static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009674 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9675 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9676 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9677 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9678 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9679 { } /* end */
9680};
9681
Takashi Iwaia9111322011-05-02 11:30:18 +02009682static const struct hda_verb alc883_haier_w66_verbs[] = {
Kailang Yang189609a2007-08-20 11:31:23 +02009683 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9685
9686 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9687
9688 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9689 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9690 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9691 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9692 { } /* end */
9693};
9694
Takashi Iwaia9111322011-05-02 11:30:18 +02009695static const struct hda_verb alc888_lenovo_sky_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009696 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9697 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9698 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9699 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9700 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9701 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9702 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9703 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9704 { } /* end */
9705};
9706
Takashi Iwaia9111322011-05-02 11:30:18 +02009707static const struct hda_verb alc888_6st_dell_verbs[] = {
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009708 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9709 { }
9710};
9711
Takashi Iwaia9111322011-05-02 11:30:18 +02009712static const struct hda_verb alc883_vaiott_verbs[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009713 /* HP */
9714 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9715 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9716
9717 /* enable unsolicited event */
9718 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9719
9720 { } /* end */
9721};
9722
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009723static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009724{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009725 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009726
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009727 spec->autocfg.hp_pins[0] = 0x1b;
9728 spec->autocfg.speaker_pins[0] = 0x14;
9729 spec->autocfg.speaker_pins[1] = 0x16;
9730 spec->autocfg.speaker_pins[2] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02009731 spec->automute = 1;
9732 spec->automute_mode = ALC_AUTOMUTE_AMP;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009733}
9734
Takashi Iwaia9111322011-05-02 11:30:18 +02009735static const struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009736 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009737 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9738 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009739 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009740 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009741};
9742
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009743/*
9744 * 2ch mode
9745 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009746static const struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009747 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9748 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9749 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9750 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009751 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009752};
9753
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009754/*
9755 * 4ch mode
9756 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009757static const struct hda_verb alc888_3st_hp_4ch_init[] = {
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009758 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9759 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9760 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9761 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9762 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9763 { } /* end */
9764};
9765
9766/*
9767 * 6ch mode
9768 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009769static const struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009770 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9771 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009772 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009773 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9774 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009775 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9776 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009777};
9778
Takashi Iwaia9111322011-05-02 11:30:18 +02009779static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009780 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009781 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009782 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009783};
9784
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009785static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009786{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009787 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009788
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009789 spec->autocfg.hp_pins[0] = 0x1b;
9790 spec->autocfg.line_out_pins[0] = 0x14;
9791 spec->autocfg.speaker_pins[0] = 0x15;
9792 spec->automute = 1;
9793 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009794}
9795
Kailang Yang272a5272007-05-14 11:00:38 +02009796/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc427172010-11-29 07:42:59 +01009797static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009798{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009799 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009800
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009801 spec->autocfg.hp_pins[0] = 0x14;
9802 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009803 spec->automute = 1;
9804 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009805}
9806
Kailang Yangccc656c2006-10-17 12:32:26 +02009807/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009808#define alc883_targa_init_hook alc882_targa_init_hook
9809#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009810
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009811static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009812{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009813 struct alc_spec *spec = codec->spec;
9814
9815 spec->autocfg.hp_pins[0] = 0x15;
9816 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009817 spec->automute = 1;
9818 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009819}
9820
9821static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9822{
Takashi Iwaid922b512011-04-28 12:18:53 +02009823 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009824 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009825}
9826
9827static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009828 unsigned int res)
9829{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009830 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009831 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009832 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009833 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009834 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02009835 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009836 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009837 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009838}
9839
Jiang zhefb97dc62008-03-06 11:07:11 +01009840/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009841static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009842{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009843 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009844
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009845 spec->autocfg.hp_pins[0] = 0x14;
9846 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009847 spec->automute = 1;
9848 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhefb97dc62008-03-06 11:07:11 +01009849}
9850
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009851static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009852{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009853 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009854
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009855 spec->autocfg.hp_pins[0] = 0x1b;
9856 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009857 spec->automute = 1;
9858 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang189609a2007-08-20 11:31:23 +02009859}
9860
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009861static void alc883_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009862{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009863 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009864
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009865 spec->autocfg.hp_pins[0] = 0x1b;
9866 spec->autocfg.line_out_pins[0] = 0x14;
9867 spec->autocfg.speaker_pins[0] = 0x15;
9868 spec->automute = 1;
9869 spec->detect_line = 1;
9870 spec->automute_lines = 1;
9871 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009872}
9873
Takashi Iwai676a9b52007-08-16 15:23:35 +02009874/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009875static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009876{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009877 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009878
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009879 spec->autocfg.hp_pins[0] = 0x14;
9880 spec->autocfg.speaker_pins[0] = 0x15;
9881 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02009882 spec->automute = 1;
9883 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009884}
9885
Takashi Iwaia9111322011-05-02 11:30:18 +02009886static const struct hda_verb alc883_acer_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009887 /* HP Pin: output 0 (0x0c) */
9888 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9889 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9890 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9891 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009892 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9893 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009894 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009895 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9896 /* eanable EAPD on medion laptop */
9897 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9898 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009899 /* enable unsolicited event */
9900 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009901 { }
9902};
9903
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009904static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009905{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009906 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009907
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009908 spec->autocfg.hp_pins[0] = 0x1b;
9909 spec->autocfg.speaker_pins[0] = 0x14;
9910 spec->autocfg.speaker_pins[1] = 0x15;
9911 spec->autocfg.speaker_pins[2] = 0x16;
9912 spec->autocfg.speaker_pins[3] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009913 spec->automute = 1;
9914 spec->automute_mode = ALC_AUTOMUTE_AMP;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009915}
9916
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009917static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009918{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009919 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009920
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009921 spec->autocfg.hp_pins[0] = 0x1b;
9922 spec->autocfg.speaker_pins[0] = 0x14;
9923 spec->autocfg.speaker_pins[1] = 0x15;
9924 spec->autocfg.speaker_pins[2] = 0x16;
9925 spec->autocfg.speaker_pins[3] = 0x17;
9926 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02009927 spec->automute = 1;
9928 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009929}
9930
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009931static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009932{
9933 struct alc_spec *spec = codec->spec;
9934
9935 spec->autocfg.hp_pins[0] = 0x15;
9936 spec->autocfg.speaker_pins[0] = 0x14;
9937 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009938 spec->automute = 1;
9939 spec->automute_mode = ALC_AUTOMUTE_AMP;
Guido Günther3e1647c2009-06-05 00:47:26 +02009940}
9941
Takashi Iwaia9111322011-05-02 11:30:18 +02009942static const struct hda_verb alc888_asus_m90v_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009943 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9944 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9945 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9946 /* enable unsolicited event */
9947 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9948 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9949 { } /* end */
9950};
9951
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009952static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009953{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009954 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009955
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009956 spec->autocfg.hp_pins[0] = 0x1b;
9957 spec->autocfg.speaker_pins[0] = 0x14;
9958 spec->autocfg.speaker_pins[1] = 0x15;
9959 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009960 spec->ext_mic.pin = 0x18;
9961 spec->int_mic.pin = 0x19;
9962 spec->ext_mic.mux_idx = 0;
9963 spec->int_mic.mux_idx = 1;
9964 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +02009965 spec->automute = 1;
9966 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009967}
9968
Takashi Iwaia9111322011-05-02 11:30:18 +02009969static const struct hda_verb alc888_asus_eee1601_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009970 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9971 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9972 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9973 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9974 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9975 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9976 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9977 /* enable unsolicited event */
9978 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9979 { } /* end */
9980};
9981
Kailang Yange2757d52008-08-26 13:17:46 +02009982static void alc883_eee1601_inithook(struct hda_codec *codec)
9983{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009984 struct alc_spec *spec = codec->spec;
9985
9986 spec->autocfg.hp_pins[0] = 0x14;
9987 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02009988 alc_hp_automute(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009989}
9990
Takashi Iwaia9111322011-05-02 11:30:18 +02009991static const struct hda_verb alc889A_mb31_verbs[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009992 /* Init rear pin (used as headphone output) */
9993 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9994 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9995 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9996 /* Init line pin (used as output in 4ch and 6ch mode) */
9997 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9998 /* Init line 2 pin (used as headphone out by default) */
9999 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
10000 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
10001 { } /* end */
10002};
10003
10004/* Mute speakers according to the headphone jack state */
10005static void alc889A_mb31_automute(struct hda_codec *codec)
10006{
10007 unsigned int present;
10008
10009 /* Mute only in 2ch or 4ch mode */
10010 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
10011 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080010012 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010013 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
10014 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
10015 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
10016 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
10017 }
10018}
10019
10020static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
10021{
10022 if ((res >> 26) == ALC880_HP_EVENT)
10023 alc889A_mb31_automute(codec);
10024}
10025
Takashi Iwai49535502009-06-30 15:28:30 +020010026
Takashi Iwaicb53c622007-08-10 17:21:45 +020010027#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +020010028#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +020010029#endif
10030
Sasha Alexandrdef319f2009-06-16 16:00:15 -040010031/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +020010032#define alc882_pcm_analog_playback alc880_pcm_analog_playback
10033#define alc882_pcm_analog_capture alc880_pcm_analog_capture
10034#define alc882_pcm_digital_playback alc880_pcm_digital_playback
10035#define alc882_pcm_digital_capture alc880_pcm_digital_capture
10036
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020010037static const hda_nid_t alc883_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010038 ALC1200_DIGOUT_NID, 0,
10039};
10040
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020010041static const hda_nid_t alc1200_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010042 ALC883_DIGOUT_NID, 0,
10043};
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010044
10045/*
10046 * configuration and preset
10047 */
Takashi Iwaiea734962011-01-17 11:29:34 +010010048static const char * const alc882_models[ALC882_MODEL_LAST] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010049 [ALC882_3ST_DIG] = "3stack-dig",
10050 [ALC882_6ST_DIG] = "6stack-dig",
10051 [ALC882_ARIMA] = "arima",
10052 [ALC882_W2JC] = "w2jc",
10053 [ALC882_TARGA] = "targa",
10054 [ALC882_ASUS_A7J] = "asus-a7j",
10055 [ALC882_ASUS_A7M] = "asus-a7m",
10056 [ALC885_MACPRO] = "macpro",
10057 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010058 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010059 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +020010060 [ALC885_MBP3] = "mbp3",
10061 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010062 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +020010063 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010064 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
10065 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +020010066 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010067 [ALC883_TARGA_DIG] = "targa-dig",
10068 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +020010069 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010070 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +020010071 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010072 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +020010073 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +020010074 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010075 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010076 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010077 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010078 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010079 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +020010080 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
10081 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +020010082 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +020010083 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010084 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010085 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010086 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010087 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010088 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +010010089 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010090 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +020010091 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010092 [ALC889A_INTEL] = "intel-alc889a",
10093 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +010010094 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010095 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +020010096 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +020010097 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010098};
10099
Takashi Iwaia9111322011-05-02 11:30:18 +020010100static const struct snd_pci_quirk alc882_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010101 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
10102
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010103 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +010010104 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +010010105 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010106 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
10107 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +020010108 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010109 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
10110 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +010010111 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +010010112 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +020010113 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
10114 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +020010115 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
10116 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +020010117 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
10118 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +010010119 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +020010120 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +010010121 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +010010122 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010123 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
10124 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +020010125 /* default Acer -- disabled as it causes more problems.
10126 * model=auto should work fine now
10127 */
10128 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +020010129
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010130 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +020010131
Lucas De Marchi25985ed2011-03-30 22:57:33 -030010132 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010133 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
10134 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +010010135 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +010010136 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -030010137 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +020010138
10139 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
10140 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
10141 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +020010142 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +020010143 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
10144 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
10145 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010146 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +010010147 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +010010148 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +020010149 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +020010150
10151 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +020010152 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010153 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +110010154 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010155 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
10156 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +020010157 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010158 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwaiebb47242011-05-02 10:37:29 +020010159 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010160
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010161 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
10162 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
10163 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010164 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +010010165 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +020010166 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010167 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +010010168 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010169 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
10170 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
10171 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
10172 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
10173 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
10174 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -070010175 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010176 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
10177 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
10178 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +010010179 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +020010180 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010181 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
10182 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +020010183 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +010010184 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +010010185 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +010010186 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +020010187 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -040010188 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +010010189 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010190 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -070010191 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010192
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010193 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +020010194 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010195 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
10196 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010197 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +010010198 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -040010199 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +020010200 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010010201 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +020010202 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +010010203 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +020010204 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010205 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +020010206 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +020010207 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010010208 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
10209 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +020010210 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +010010211 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +010010212 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +020010213 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +020010214
Jiang zhe17bba1b2008-06-04 12:11:07 +020010215 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
10216 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +110010217 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010218 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
10219 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
10220 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -040010221 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010222
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010223 {}
10224};
10225
Takashi Iwai49535502009-06-30 15:28:30 +020010226/* codec SSID table for Intel Mac */
Takashi Iwaia9111322011-05-02 11:30:18 +020010227static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010228 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
10229 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
10230 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
10231 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
10232 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
10233 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
10234 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -040010235 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -070010236 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -070010237 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -070010238 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +020010239 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
10240 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
10241 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010242 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +020010243 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +100010244 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010245 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
10246 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +020010247 */
10248 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010249 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010250 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +020010251 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010252};
10253
Takashi Iwaia9111322011-05-02 11:30:18 +020010254static const struct alc_config_preset alc882_presets[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010255 [ALC882_3ST_DIG] = {
10256 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010257 .init_verbs = { alc882_base_init_verbs,
10258 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010259 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10260 .dac_nids = alc882_dac_nids,
10261 .dig_out_nid = ALC882_DIGOUT_NID,
10262 .dig_in_nid = ALC882_DIGIN_NID,
10263 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10264 .channel_mode = alc882_ch_modes,
10265 .need_dac_fix = 1,
10266 .input_mux = &alc882_capture_source,
10267 },
10268 [ALC882_6ST_DIG] = {
10269 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010270 .init_verbs = { alc882_base_init_verbs,
10271 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010272 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10273 .dac_nids = alc882_dac_nids,
10274 .dig_out_nid = ALC882_DIGOUT_NID,
10275 .dig_in_nid = ALC882_DIGIN_NID,
10276 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10277 .channel_mode = alc882_sixstack_modes,
10278 .input_mux = &alc882_capture_source,
10279 },
10280 [ALC882_ARIMA] = {
10281 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010282 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10283 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010284 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10285 .dac_nids = alc882_dac_nids,
10286 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10287 .channel_mode = alc882_sixstack_modes,
10288 .input_mux = &alc882_capture_source,
10289 },
10290 [ALC882_W2JC] = {
10291 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010292 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10293 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010294 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10295 .dac_nids = alc882_dac_nids,
10296 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10297 .channel_mode = alc880_threestack_modes,
10298 .need_dac_fix = 1,
10299 .input_mux = &alc882_capture_source,
10300 .dig_out_nid = ALC882_DIGOUT_NID,
10301 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010302 [ALC885_MBA21] = {
10303 .mixers = { alc885_mba21_mixer },
10304 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
10305 .num_dacs = 2,
10306 .dac_nids = alc882_dac_nids,
10307 .channel_mode = alc885_mba21_ch_modes,
10308 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10309 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010310 .unsol_event = alc_sku_unsol_event,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010311 .setup = alc885_mba21_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010312 .init_hook = alc_hp_automute,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010313 },
Takashi Iwai49535502009-06-30 15:28:30 +020010314 [ALC885_MBP3] = {
10315 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
10316 .init_verbs = { alc885_mbp3_init_verbs,
10317 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010318 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +020010319 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010320 .hp_nid = 0x04,
10321 .channel_mode = alc885_mbp_4ch_modes,
10322 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +020010323 .input_mux = &alc882_capture_source,
10324 .dig_out_nid = ALC882_DIGOUT_NID,
10325 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010326 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010327 .setup = alc885_mbp3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010328 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010329 },
10330 [ALC885_MB5] = {
10331 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
10332 .init_verbs = { alc885_mb5_init_verbs,
10333 alc880_gpio1_init_verbs },
10334 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10335 .dac_nids = alc882_dac_nids,
10336 .channel_mode = alc885_mb5_6ch_modes,
10337 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10338 .input_mux = &mb5_capture_source,
10339 .dig_out_nid = ALC882_DIGOUT_NID,
10340 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010341 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010342 .setup = alc885_mb5_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010343 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010344 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010345 [ALC885_MACMINI3] = {
10346 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10347 .init_verbs = { alc885_macmini3_init_verbs,
10348 alc880_gpio1_init_verbs },
10349 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10350 .dac_nids = alc882_dac_nids,
10351 .channel_mode = alc885_macmini3_6ch_modes,
10352 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10353 .input_mux = &macmini3_capture_source,
10354 .dig_out_nid = ALC882_DIGOUT_NID,
10355 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010356 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010357 .setup = alc885_macmini3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010358 .init_hook = alc_hp_automute,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010359 },
Takashi Iwai49535502009-06-30 15:28:30 +020010360 [ALC885_MACPRO] = {
10361 .mixers = { alc882_macpro_mixer },
10362 .init_verbs = { alc882_macpro_init_verbs },
10363 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10364 .dac_nids = alc882_dac_nids,
10365 .dig_out_nid = ALC882_DIGOUT_NID,
10366 .dig_in_nid = ALC882_DIGIN_NID,
10367 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10368 .channel_mode = alc882_ch_modes,
10369 .input_mux = &alc882_capture_source,
10370 .init_hook = alc885_macpro_init_hook,
10371 },
10372 [ALC885_IMAC24] = {
10373 .mixers = { alc885_imac24_mixer },
10374 .init_verbs = { alc885_imac24_init_verbs },
10375 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10376 .dac_nids = alc882_dac_nids,
10377 .dig_out_nid = ALC882_DIGOUT_NID,
10378 .dig_in_nid = ALC882_DIGIN_NID,
10379 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10380 .channel_mode = alc882_ch_modes,
10381 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010382 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010383 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +020010384 .init_hook = alc885_imac24_init_hook,
10385 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010386 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010387 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010388 .init_verbs = { alc885_imac91_init_verbs,
10389 alc880_gpio1_init_verbs },
10390 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10391 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010392 .channel_mode = alc885_mba21_ch_modes,
10393 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10394 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010395 .dig_out_nid = ALC882_DIGOUT_NID,
10396 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010397 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010398 .setup = alc885_imac91_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010399 .init_hook = alc_hp_automute,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010400 },
Takashi Iwai49535502009-06-30 15:28:30 +020010401 [ALC882_TARGA] = {
10402 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010403 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010404 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010405 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10406 .dac_nids = alc882_dac_nids,
10407 .dig_out_nid = ALC882_DIGOUT_NID,
10408 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10409 .adc_nids = alc882_adc_nids,
10410 .capsrc_nids = alc882_capsrc_nids,
10411 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10412 .channel_mode = alc882_3ST_6ch_modes,
10413 .need_dac_fix = 1,
10414 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010415 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010416 .setup = alc882_targa_setup,
10417 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010418 },
10419 [ALC882_ASUS_A7J] = {
10420 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010421 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10422 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010423 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10424 .dac_nids = alc882_dac_nids,
10425 .dig_out_nid = ALC882_DIGOUT_NID,
10426 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10427 .adc_nids = alc882_adc_nids,
10428 .capsrc_nids = alc882_capsrc_nids,
10429 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10430 .channel_mode = alc882_3ST_6ch_modes,
10431 .need_dac_fix = 1,
10432 .input_mux = &alc882_capture_source,
10433 },
10434 [ALC882_ASUS_A7M] = {
10435 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010436 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10437 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +020010438 alc882_asus_a7m_verbs },
10439 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10440 .dac_nids = alc882_dac_nids,
10441 .dig_out_nid = ALC882_DIGOUT_NID,
10442 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10443 .channel_mode = alc880_threestack_modes,
10444 .need_dac_fix = 1,
10445 .input_mux = &alc882_capture_source,
10446 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010447 [ALC883_3ST_2ch_DIG] = {
10448 .mixers = { alc883_3ST_2ch_mixer },
10449 .init_verbs = { alc883_init_verbs },
10450 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10451 .dac_nids = alc883_dac_nids,
10452 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010453 .dig_in_nid = ALC883_DIGIN_NID,
10454 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10455 .channel_mode = alc883_3ST_2ch_modes,
10456 .input_mux = &alc883_capture_source,
10457 },
10458 [ALC883_3ST_6ch_DIG] = {
10459 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10460 .init_verbs = { alc883_init_verbs },
10461 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10462 .dac_nids = alc883_dac_nids,
10463 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010464 .dig_in_nid = ALC883_DIGIN_NID,
10465 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10466 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010467 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010468 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010469 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010470 [ALC883_3ST_6ch] = {
10471 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10472 .init_verbs = { alc883_init_verbs },
10473 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10474 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010475 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10476 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010477 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010478 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010479 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010480 [ALC883_3ST_6ch_INTEL] = {
10481 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10482 .init_verbs = { alc883_init_verbs },
10483 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10484 .dac_nids = alc883_dac_nids,
10485 .dig_out_nid = ALC883_DIGOUT_NID,
10486 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010487 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010488 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10489 .channel_mode = alc883_3ST_6ch_intel_modes,
10490 .need_dac_fix = 1,
10491 .input_mux = &alc883_3stack_6ch_intel,
10492 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010493 [ALC889A_INTEL] = {
10494 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010495 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10496 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010497 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10498 .dac_nids = alc883_dac_nids,
10499 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10500 .adc_nids = alc889_adc_nids,
10501 .dig_out_nid = ALC883_DIGOUT_NID,
10502 .dig_in_nid = ALC883_DIGIN_NID,
10503 .slave_dig_outs = alc883_slave_dig_outs,
10504 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10505 .channel_mode = alc889_8ch_intel_modes,
10506 .capsrc_nids = alc889_capsrc_nids,
10507 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010508 .setup = alc889_automute_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010509 .init_hook = alc_hp_automute,
10510 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010511 .need_dac_fix = 1,
10512 },
10513 [ALC889_INTEL] = {
10514 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10515 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010516 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010517 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10518 .dac_nids = alc883_dac_nids,
10519 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10520 .adc_nids = alc889_adc_nids,
10521 .dig_out_nid = ALC883_DIGOUT_NID,
10522 .dig_in_nid = ALC883_DIGIN_NID,
10523 .slave_dig_outs = alc883_slave_dig_outs,
10524 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10525 .channel_mode = alc889_8ch_intel_modes,
10526 .capsrc_nids = alc889_capsrc_nids,
10527 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010528 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010529 .init_hook = alc889_intel_init_hook,
Takashi Iwaid922b512011-04-28 12:18:53 +020010530 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010531 .need_dac_fix = 1,
10532 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010533 [ALC883_6ST_DIG] = {
10534 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10535 .init_verbs = { alc883_init_verbs },
10536 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10537 .dac_nids = alc883_dac_nids,
10538 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010539 .dig_in_nid = ALC883_DIGIN_NID,
10540 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10541 .channel_mode = alc883_sixstack_modes,
10542 .input_mux = &alc883_capture_source,
10543 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010544 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010545 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010546 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10547 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010548 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10549 .dac_nids = alc883_dac_nids,
10550 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010551 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10552 .channel_mode = alc883_3ST_6ch_modes,
10553 .need_dac_fix = 1,
10554 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010555 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010556 .setup = alc882_targa_setup,
10557 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010558 },
10559 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010560 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010561 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10562 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010563 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10564 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010565 .adc_nids = alc883_adc_nids_alt,
10566 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010567 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010568 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010569 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10570 .channel_mode = alc883_3ST_2ch_modes,
10571 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010572 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010573 .setup = alc882_targa_setup,
10574 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010575 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010576 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010577 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10578 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010579 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010580 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010581 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10582 .dac_nids = alc883_dac_nids,
10583 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10584 .adc_nids = alc883_adc_nids_rev,
10585 .capsrc_nids = alc883_capsrc_nids_rev,
10586 .dig_out_nid = ALC883_DIGOUT_NID,
10587 .dig_in_nid = ALC883_DIGIN_NID,
10588 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10589 .channel_mode = alc883_4ST_8ch_modes,
10590 .need_dac_fix = 1,
10591 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010592 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010593 .setup = alc882_targa_setup,
10594 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010595 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010596 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010597 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010598 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10599 * and the headphone jack. Turn this on and rely on the
10600 * standard mute methods whenever the user wants to turn
10601 * these outputs off.
10602 */
10603 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10604 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10605 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010606 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10607 .channel_mode = alc883_3ST_2ch_modes,
10608 .input_mux = &alc883_capture_source,
10609 },
Tobin Davis2880a862007-08-07 11:50:26 +020010610 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010611 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010612 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010613 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10614 .dac_nids = alc883_dac_nids,
10615 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010616 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10617 .channel_mode = alc883_3ST_2ch_modes,
10618 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010619 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010620 .setup = alc883_acer_aspire_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010621 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010622 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010623 [ALC888_ACER_ASPIRE_4930G] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +010010624 .mixers = { alc888_acer_aspire_4930g_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010625 alc883_chmode_mixer },
10626 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10627 alc888_acer_aspire_4930g_verbs },
10628 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10629 .dac_nids = alc883_dac_nids,
10630 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10631 .adc_nids = alc883_adc_nids_rev,
10632 .capsrc_nids = alc883_capsrc_nids_rev,
10633 .dig_out_nid = ALC883_DIGOUT_NID,
10634 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10635 .channel_mode = alc883_3ST_6ch_modes,
10636 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010637 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010638 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010639 ARRAY_SIZE(alc888_2_capture_sources),
10640 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010641 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010642 .setup = alc888_acer_aspire_4930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010643 .init_hook = alc_hp_automute,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010644 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010645 [ALC888_ACER_ASPIRE_6530G] = {
10646 .mixers = { alc888_acer_aspire_6530_mixer },
10647 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10648 alc888_acer_aspire_6530g_verbs },
10649 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10650 .dac_nids = alc883_dac_nids,
10651 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10652 .adc_nids = alc883_adc_nids_rev,
10653 .capsrc_nids = alc883_capsrc_nids_rev,
10654 .dig_out_nid = ALC883_DIGOUT_NID,
10655 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10656 .channel_mode = alc883_3ST_2ch_modes,
10657 .num_mux_defs =
10658 ARRAY_SIZE(alc888_2_capture_sources),
10659 .input_mux = alc888_acer_aspire_6530_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010660 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010661 .setup = alc888_acer_aspire_6530g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010662 .init_hook = alc_hp_automute,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010663 },
Hector Martin3b315d72009-06-02 10:54:19 +020010664 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010665 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010666 alc883_chmode_mixer },
10667 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010668 alc889_acer_aspire_8930g_verbs,
10669 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010670 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10671 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010672 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10673 .adc_nids = alc889_adc_nids,
10674 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010675 .dig_out_nid = ALC883_DIGOUT_NID,
10676 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10677 .channel_mode = alc883_3ST_6ch_modes,
10678 .need_dac_fix = 1,
10679 .const_channel_count = 6,
10680 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010681 ARRAY_SIZE(alc889_capture_sources),
10682 .input_mux = alc889_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010683 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010684 .setup = alc889_acer_aspire_8930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010685 .init_hook = alc_hp_automute,
Hector Martinf5de24b2009-12-20 22:51:31 +010010686#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010687 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010688#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010689 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010690 [ALC888_ACER_ASPIRE_7730G] = {
10691 .mixers = { alc883_3ST_6ch_mixer,
10692 alc883_chmode_mixer },
10693 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10694 alc888_acer_aspire_7730G_verbs },
10695 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10696 .dac_nids = alc883_dac_nids,
10697 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10698 .adc_nids = alc883_adc_nids_rev,
10699 .capsrc_nids = alc883_capsrc_nids_rev,
10700 .dig_out_nid = ALC883_DIGOUT_NID,
10701 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10702 .channel_mode = alc883_3ST_6ch_modes,
10703 .need_dac_fix = 1,
10704 .const_channel_count = 6,
10705 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010706 .unsol_event = alc_sku_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010707 .setup = alc888_acer_aspire_7730g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010708 .init_hook = alc_hp_automute,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010709 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010710 [ALC883_MEDION] = {
10711 .mixers = { alc883_fivestack_mixer,
10712 alc883_chmode_mixer },
10713 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010714 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010715 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10716 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010717 .adc_nids = alc883_adc_nids_alt,
10718 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010719 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010720 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10721 .channel_mode = alc883_sixstack_modes,
10722 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010723 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010724 [ALC883_MEDION_WIM2160] = {
10725 .mixers = { alc883_medion_wim2160_mixer },
10726 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10727 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10728 .dac_nids = alc883_dac_nids,
10729 .dig_out_nid = ALC883_DIGOUT_NID,
10730 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10731 .adc_nids = alc883_adc_nids,
10732 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10733 .channel_mode = alc883_3ST_2ch_modes,
10734 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010735 .unsol_event = alc_sku_unsol_event,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010736 .setup = alc883_medion_wim2160_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010737 .init_hook = alc_hp_automute,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010738 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010739 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010740 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010741 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10742 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10743 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010744 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10745 .channel_mode = alc883_3ST_2ch_modes,
10746 .input_mux = &alc883_capture_source,
10747 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010748 [ALC883_CLEVO_M540R] = {
10749 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10750 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10751 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10752 .dac_nids = alc883_dac_nids,
10753 .dig_out_nid = ALC883_DIGOUT_NID,
10754 .dig_in_nid = ALC883_DIGIN_NID,
10755 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10756 .channel_mode = alc883_3ST_6ch_clevo_modes,
10757 .need_dac_fix = 1,
10758 .input_mux = &alc883_capture_source,
10759 /* This machine has the hardware HP auto-muting, thus
10760 * we need no software mute via unsol event
10761 */
10762 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010763 [ALC883_CLEVO_M720] = {
10764 .mixers = { alc883_clevo_m720_mixer },
10765 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010766 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10767 .dac_nids = alc883_dac_nids,
10768 .dig_out_nid = ALC883_DIGOUT_NID,
10769 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10770 .channel_mode = alc883_3ST_2ch_modes,
10771 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010772 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010773 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010774 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010775 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010776 [ALC883_LENOVO_101E_2ch] = {
10777 .mixers = { alc883_lenovo_101e_2ch_mixer},
10778 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10779 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10780 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010781 .adc_nids = alc883_adc_nids_alt,
10782 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010783 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010784 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10785 .channel_mode = alc883_3ST_2ch_modes,
10786 .input_mux = &alc883_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010787 .setup = alc883_lenovo_101e_setup,
10788 .unsol_event = alc_sku_unsol_event,
10789 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010790 },
Kailang Yang272a5272007-05-14 11:00:38 +020010791 [ALC883_LENOVO_NB0763] = {
10792 .mixers = { alc883_lenovo_nb0763_mixer },
10793 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10794 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10795 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010796 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10797 .channel_mode = alc883_3ST_2ch_modes,
10798 .need_dac_fix = 1,
10799 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010800 .unsol_event = alc_sku_unsol_event,
Takashi Iwaidc427172010-11-29 07:42:59 +010010801 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010802 .init_hook = alc_hp_automute,
Kailang Yang272a5272007-05-14 11:00:38 +020010803 },
10804 [ALC888_LENOVO_MS7195_DIG] = {
10805 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10806 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10807 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10808 .dac_nids = alc883_dac_nids,
10809 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010810 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10811 .channel_mode = alc883_3ST_6ch_modes,
10812 .need_dac_fix = 1,
10813 .input_mux = &alc883_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010814 .unsol_event = alc_sku_unsol_event,
10815 .setup = alc888_lenovo_ms7195_setup,
10816 .init_hook = alc_inithook,
Kailang Yang189609a2007-08-20 11:31:23 +020010817 },
10818 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010819 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010820 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10821 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10822 .dac_nids = alc883_dac_nids,
10823 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010824 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10825 .channel_mode = alc883_3ST_2ch_modes,
10826 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010827 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010828 .setup = alc883_haier_w66_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010829 .init_hook = alc_hp_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010830 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010831 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010832 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010833 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010834 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10835 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010836 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10837 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010838 .need_dac_fix = 1,
10839 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010840 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010841 .setup = alc888_3st_hp_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010842 .init_hook = alc_hp_automute,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010843 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010844 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010845 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010846 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10847 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10848 .dac_nids = alc883_dac_nids,
10849 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010850 .dig_in_nid = ALC883_DIGIN_NID,
10851 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10852 .channel_mode = alc883_sixstack_modes,
10853 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010854 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010855 .setup = alc888_6st_dell_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010856 .init_hook = alc_hp_automute,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010857 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010858 [ALC883_MITAC] = {
10859 .mixers = { alc883_mitac_mixer },
10860 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10861 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10862 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010863 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10864 .channel_mode = alc883_3ST_2ch_modes,
10865 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010866 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010867 .setup = alc883_mitac_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010868 .init_hook = alc_hp_automute,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010869 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010870 [ALC883_FUJITSU_PI2515] = {
10871 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10872 .init_verbs = { alc883_init_verbs,
10873 alc883_2ch_fujitsu_pi2515_verbs},
10874 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10875 .dac_nids = alc883_dac_nids,
10876 .dig_out_nid = ALC883_DIGOUT_NID,
10877 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10878 .channel_mode = alc883_3ST_2ch_modes,
10879 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010880 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010881 .setup = alc883_2ch_fujitsu_pi2515_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010882 .init_hook = alc_hp_automute,
Jiang zhefb97dc62008-03-06 11:07:11 +010010883 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010884 [ALC888_FUJITSU_XA3530] = {
10885 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10886 .init_verbs = { alc883_init_verbs,
10887 alc888_fujitsu_xa3530_verbs },
10888 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10889 .dac_nids = alc883_dac_nids,
10890 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10891 .adc_nids = alc883_adc_nids_rev,
10892 .capsrc_nids = alc883_capsrc_nids_rev,
10893 .dig_out_nid = ALC883_DIGOUT_NID,
10894 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10895 .channel_mode = alc888_4ST_8ch_intel_modes,
10896 .num_mux_defs =
10897 ARRAY_SIZE(alc888_2_capture_sources),
10898 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010899 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010900 .setup = alc888_fujitsu_xa3530_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010901 .init_hook = alc_hp_automute,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010902 },
Kailang Yange2757d52008-08-26 13:17:46 +020010903 [ALC888_LENOVO_SKY] = {
10904 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10905 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10906 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10907 .dac_nids = alc883_dac_nids,
10908 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010909 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10910 .channel_mode = alc883_sixstack_modes,
10911 .need_dac_fix = 1,
10912 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010913 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010914 .setup = alc888_lenovo_sky_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010915 .init_hook = alc_hp_automute,
Kailang Yange2757d52008-08-26 13:17:46 +020010916 },
10917 [ALC888_ASUS_M90V] = {
10918 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10919 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10920 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10921 .dac_nids = alc883_dac_nids,
10922 .dig_out_nid = ALC883_DIGOUT_NID,
10923 .dig_in_nid = ALC883_DIGIN_NID,
10924 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10925 .channel_mode = alc883_3ST_6ch_modes,
10926 .need_dac_fix = 1,
10927 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010928 .unsol_event = alc_sku_unsol_event,
10929 .setup = alc883_mode2_setup,
10930 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010931 },
10932 [ALC888_ASUS_EEE1601] = {
10933 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010934 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010935 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10936 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10937 .dac_nids = alc883_dac_nids,
10938 .dig_out_nid = ALC883_DIGOUT_NID,
10939 .dig_in_nid = ALC883_DIGIN_NID,
10940 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10941 .channel_mode = alc883_3ST_2ch_modes,
10942 .need_dac_fix = 1,
10943 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010944 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010945 .init_hook = alc883_eee1601_inithook,
10946 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010947 [ALC1200_ASUS_P5Q] = {
10948 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10949 .init_verbs = { alc883_init_verbs },
10950 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10951 .dac_nids = alc883_dac_nids,
10952 .dig_out_nid = ALC1200_DIGOUT_NID,
10953 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010954 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010955 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10956 .channel_mode = alc883_sixstack_modes,
10957 .input_mux = &alc883_capture_source,
10958 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010959 [ALC889A_MB31] = {
10960 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10961 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10962 alc880_gpio1_init_verbs },
10963 .adc_nids = alc883_adc_nids,
10964 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010965 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010966 .dac_nids = alc883_dac_nids,
10967 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10968 .channel_mode = alc889A_mb31_6ch_modes,
10969 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10970 .input_mux = &alc889A_mb31_capture_source,
10971 .dig_out_nid = ALC883_DIGOUT_NID,
10972 .unsol_event = alc889A_mb31_unsol_event,
10973 .init_hook = alc889A_mb31_automute,
10974 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010975 [ALC883_SONY_VAIO_TT] = {
10976 .mixers = { alc883_vaiott_mixer },
10977 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10978 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10979 .dac_nids = alc883_dac_nids,
10980 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10981 .channel_mode = alc883_3ST_2ch_modes,
10982 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010983 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010984 .setup = alc883_vaiott_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010985 .init_hook = alc_hp_automute,
Guido Günther3e1647c2009-06-05 00:47:26 +020010986 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010987};
10988
10989
10990/*
Takashi Iwai49535502009-06-30 15:28:30 +020010991 * Pin config fixes
10992 */
10993enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010994 PINFIX_ABIT_AW9D_MAX,
David Henningsson32eea382011-03-04 13:37:50 +010010995 PINFIX_LENOVO_Y530,
Takashi Iwai954a29c2010-07-30 10:55:44 +020010996 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010997 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai49535502009-06-30 15:28:30 +020010998};
10999
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020011000static const struct alc_fixup alc882_fixups[] = {
11001 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011002 .type = ALC_FIXUP_PINS,
11003 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020011004 { 0x15, 0x01080104 }, /* side */
11005 { 0x16, 0x01011012 }, /* rear */
11006 { 0x17, 0x01016011 }, /* clfe */
11007 { }
11008 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020011009 },
David Henningsson32eea382011-03-04 13:37:50 +010011010 [PINFIX_LENOVO_Y530] = {
11011 .type = ALC_FIXUP_PINS,
11012 .v.pins = (const struct alc_pincfg[]) {
11013 { 0x15, 0x99130112 }, /* rear int speakers */
11014 { 0x16, 0x99130111 }, /* subwoofer */
11015 { }
11016 }
11017 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020011018 [PINFIX_PB_M5210] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011019 .type = ALC_FIXUP_VERBS,
11020 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020011021 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
11022 {}
11023 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020011024 },
David Henningssonc3d226a2010-10-14 15:42:08 +020011025 [PINFIX_ACER_ASPIRE_7736] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011026 .type = ALC_FIXUP_SKU,
11027 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonc3d226a2010-10-14 15:42:08 +020011028 },
Takashi Iwai49535502009-06-30 15:28:30 +020011029};
11030
Takashi Iwaia9111322011-05-02 11:30:18 +020011031static const struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020011032 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
David Henningsson32eea382011-03-04 13:37:50 +010011033 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
Takashi Iwai49535502009-06-30 15:28:30 +020011034 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020011035 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai49535502009-06-30 15:28:30 +020011036 {}
11037};
11038
11039/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011040 * BIOS auto configuration
11041 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020011042static int alc882_auto_create_input_ctls(struct hda_codec *codec,
11043 const struct auto_pin_cfg *cfg)
11044{
11045 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
11046}
11047
Takashi Iwai49535502009-06-30 15:28:30 +020011048static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011049 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020011050 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011051{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011052 int idx;
11053
Takashi Iwai489008c2010-04-07 09:06:00 +020011054 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011055 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011056
Takashi Iwai489008c2010-04-07 09:06:00 +020011057 if (dac == 0x25)
11058 idx = 4;
11059 else if (dac >= 0x02 && dac <= 0x05)
11060 idx = dac - 2;
11061 else
11062 return;
11063 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011064}
11065
Takashi Iwai49535502009-06-30 15:28:30 +020011066static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011067{
11068 struct alc_spec *spec = codec->spec;
11069 int i;
11070
11071 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011072 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020011073 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011074 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +020011075 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020011076 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011077 }
11078}
11079
Takashi Iwai49535502009-06-30 15:28:30 +020011080static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011081{
11082 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020011083 hda_nid_t pin, dac;
Takashi Iwai5855fb82010-09-16 18:24:02 +020011084 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011085
David Henningsson0a3fabe2011-03-04 16:54:52 +010011086 if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) {
11087 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
11088 pin = spec->autocfg.hp_pins[i];
11089 if (!pin)
11090 break;
11091 dac = spec->multiout.hp_nid;
11092 if (!dac)
11093 dac = spec->multiout.dac_nids[0]; /* to front */
11094 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
11095 }
Takashi Iwai489008c2010-04-07 09:06:00 +020011096 }
David Henningsson0a3fabe2011-03-04 16:54:52 +010011097
11098 if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) {
11099 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
11100 pin = spec->autocfg.speaker_pins[i];
11101 if (!pin)
11102 break;
11103 dac = spec->multiout.extra_out_nid[0];
11104 if (!dac)
11105 dac = spec->multiout.dac_nids[0]; /* to front */
11106 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
11107 }
Takashi Iwai489008c2010-04-07 09:06:00 +020011108 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011109}
11110
Takashi Iwai49535502009-06-30 15:28:30 +020011111static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011112{
11113 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011114 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011115 int i;
11116
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011117 for (i = 0; i < cfg->num_inputs; i++) {
11118 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai30ea0982010-09-16 18:47:56 +020011119 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai49535502009-06-30 15:28:30 +020011120 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
11121 snd_hda_codec_write(codec, nid, 0,
11122 AC_VERB_SET_AMP_GAIN_MUTE,
11123 AMP_OUT_MUTE);
11124 }
11125}
11126
11127static void alc882_auto_init_input_src(struct hda_codec *codec)
11128{
11129 struct alc_spec *spec = codec->spec;
11130 int c;
11131
11132 for (c = 0; c < spec->num_adc_nids; c++) {
11133 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
11134 hda_nid_t nid = spec->capsrc_nids[c];
11135 unsigned int mux_idx;
11136 const struct hda_input_mux *imux;
11137 int conns, mute, idx, item;
11138
Takashi Iwai10696aa2011-04-07 12:46:45 +020011139 /* mute ADC */
11140 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
11141 AC_VERB_SET_AMP_GAIN_MUTE,
11142 AMP_IN_MUTE(0));
11143
Takashi Iwai49535502009-06-30 15:28:30 +020011144 conns = snd_hda_get_connections(codec, nid, conn_list,
11145 ARRAY_SIZE(conn_list));
11146 if (conns < 0)
11147 continue;
11148 mux_idx = c >= spec->num_mux_defs ? 0 : c;
11149 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010011150 if (!imux->num_items && mux_idx > 0)
11151 imux = &spec->input_mux[0];
Takashi Iwai49535502009-06-30 15:28:30 +020011152 for (idx = 0; idx < conns; idx++) {
11153 /* if the current connection is the selected one,
11154 * unmute it as default - otherwise mute it
11155 */
11156 mute = AMP_IN_MUTE(idx);
11157 for (item = 0; item < imux->num_items; item++) {
11158 if (imux->items[item].index == idx) {
11159 if (spec->cur_mux[c] == item)
11160 mute = AMP_IN_UNMUTE(idx);
11161 break;
11162 }
11163 }
11164 /* check if we have a selector or mixer
11165 * we could check for the widget type instead, but
11166 * just check for Amp-In presence (in case of mixer
11167 * without amp-in there is something wrong, this
11168 * function shouldn't be used or capsrc nid is wrong)
11169 */
11170 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011171 snd_hda_codec_write(codec, nid, 0,
11172 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020011173 mute);
11174 else if (mute != AMP_IN_MUTE(idx))
11175 snd_hda_codec_write(codec, nid, 0,
11176 AC_VERB_SET_CONNECT_SEL,
11177 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011178 }
11179 }
11180}
11181
Takashi Iwai49535502009-06-30 15:28:30 +020011182/* add mic boosts if needed */
11183static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011184{
11185 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011186 struct auto_pin_cfg *cfg = &spec->autocfg;
David Henningsson5322bf22011-01-05 11:03:56 +010011187 int i, err;
Takashi Iwai53e8c322010-12-17 15:23:41 +010011188 int type_idx = 0;
Takashi Iwai49535502009-06-30 15:28:30 +020011189 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010011190 const char *prev_label = NULL;
Takashi Iwai49535502009-06-30 15:28:30 +020011191
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011192 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020011193 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011194 break;
11195 nid = cfg->inputs[i].pin;
11196 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
David Henningsson5322bf22011-01-05 11:03:56 +010011197 const char *label;
11198 char boost_label[32];
11199
11200 label = hda_get_autocfg_input_label(codec, cfg, i);
11201 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai53e8c322010-12-17 15:23:41 +010011202 type_idx++;
11203 else
11204 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +010011205 prev_label = label;
11206
11207 snprintf(boost_label, sizeof(boost_label),
11208 "%s Boost Volume", label);
11209 err = add_control(spec, ALC_CTL_WIDGET_VOL,
11210 boost_label, type_idx,
Takashi Iwai49535502009-06-30 15:28:30 +020011211 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020011212 if (err < 0)
11213 return err;
11214 }
Takashi Iwai49535502009-06-30 15:28:30 +020011215 }
11216 return 0;
11217}
11218
11219/* almost identical with ALC880 parser... */
11220static int alc882_parse_auto_config(struct hda_codec *codec)
11221{
11222 struct alc_spec *spec = codec->spec;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011223 static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020011224 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011225
Takashi Iwai05f5f472009-08-25 13:10:18 +020011226 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
11227 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011228 if (err < 0)
11229 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011230 if (!spec->autocfg.line_outs)
11231 return 0; /* can't find valid BIOS pin config */
11232
11233 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
11234 if (err < 0)
11235 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020011236 err = alc_auto_add_multi_channel_mode(codec);
11237 if (err < 0)
11238 return err;
Takashi Iwai569ed342011-01-19 10:14:46 +010011239 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
Takashi Iwai05f5f472009-08-25 13:10:18 +020011240 if (err < 0)
11241 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020011242 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
11243 "Headphone");
11244 if (err < 0)
11245 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011246 err = alc880_auto_create_extra_out(spec,
11247 spec->autocfg.speaker_pins[0],
11248 "Speaker");
11249 if (err < 0)
11250 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020011251 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
11252 if (err < 0)
11253 return err;
11254
11255 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
11256
Takashi Iwai757899a2010-07-30 10:48:14 +020011257 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020011258
11259 if (spec->kctls.list)
11260 add_mixer(spec, spec->kctls.list);
11261
11262 add_verb(spec, alc883_auto_init_verbs);
11263 /* if ADC 0x07 is available, initialize it, too */
11264 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
11265 add_verb(spec, alc882_adc1_init_verbs);
11266
11267 spec->num_mux_defs = 1;
11268 spec->input_mux = &spec->private_imux[0];
11269
Kailang Yang6227cdc2010-02-25 08:36:52 +010011270 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020011271
11272 err = alc_auto_add_mic_boost(codec);
11273 if (err < 0)
11274 return err;
11275
Takashi Iwai776e1842007-08-29 15:07:11 +020011276 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011277}
11278
11279/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020011280static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011281{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011282 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020011283 alc882_auto_init_multi_out(codec);
11284 alc882_auto_init_hp_out(codec);
11285 alc882_auto_init_analog_input(codec);
11286 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020011287 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010011288 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020011289 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011290}
11291
Takashi Iwai49535502009-06-30 15:28:30 +020011292static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011293{
11294 struct alc_spec *spec;
11295 int err, board_config;
11296
11297 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
11298 if (spec == NULL)
11299 return -ENOMEM;
11300
11301 codec->spec = spec;
11302
Takashi Iwai49535502009-06-30 15:28:30 +020011303 switch (codec->vendor_id) {
11304 case 0x10ec0882:
11305 case 0x10ec0885:
11306 break;
11307 default:
11308 /* ALC883 and variants */
11309 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
11310 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011311 }
11312
Takashi Iwai49535502009-06-30 15:28:30 +020011313 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
11314 alc882_models,
11315 alc882_cfg_tbl);
11316
11317 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
11318 board_config = snd_hda_check_board_codec_sid_config(codec,
11319 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
11320
11321 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020011322 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020011323 codec->chip_name);
11324 board_config = ALC882_AUTO;
11325 }
11326
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011327 if (board_config == ALC882_AUTO) {
11328 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
11329 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
11330 }
Takashi Iwai49535502009-06-30 15:28:30 +020011331
David Henningsson90622912010-10-14 14:50:18 +020011332 alc_auto_parse_customize_define(codec);
11333
Takashi Iwai49535502009-06-30 15:28:30 +020011334 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011335 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020011336 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011337 if (err < 0) {
11338 alc_free(codec);
11339 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011340 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011341 printk(KERN_INFO
11342 "hda_codec: Cannot set up configuration "
11343 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020011344 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011345 }
11346 }
11347
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011348 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020011349 err = snd_hda_attach_beep_device(codec, 0x1);
11350 if (err < 0) {
11351 alc_free(codec);
11352 return err;
11353 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011354 }
11355
Takashi Iwai49535502009-06-30 15:28:30 +020011356 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011357 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011358
Takashi Iwai49535502009-06-30 15:28:30 +020011359 spec->stream_analog_playback = &alc882_pcm_analog_playback;
11360 spec->stream_analog_capture = &alc882_pcm_analog_capture;
11361 /* FIXME: setup DAC5 */
11362 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
11363 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
11364
11365 spec->stream_digital_playback = &alc882_pcm_digital_playback;
11366 spec->stream_digital_capture = &alc882_pcm_digital_capture;
11367
Takashi Iwai49535502009-06-30 15:28:30 +020011368 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011369 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020011370 spec->num_adc_nids = 0;
11371 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011372 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020011373 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011374 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020011375 hda_nid_t nid = alc882_adc_nids[i];
11376 unsigned int wcap = get_wcaps(codec, nid);
11377 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020011378 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020011379 if (wcap != AC_WID_AUD_IN)
11380 continue;
11381 spec->private_adc_nids[spec->num_adc_nids] = nid;
11382 err = snd_hda_get_connections(codec, nid, &cap, 1);
11383 if (err < 0)
11384 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011385 err = snd_hda_get_connections(codec, cap, items,
11386 ARRAY_SIZE(items));
11387 if (err < 0)
11388 continue;
11389 for (j = 0; j < imux->num_items; j++)
11390 if (imux->items[j].index >= err)
11391 break;
11392 if (j < imux->num_items)
11393 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020011394 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
11395 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011396 }
Takashi Iwai49535502009-06-30 15:28:30 +020011397 spec->adc_nids = spec->private_adc_nids;
11398 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020011399 }
11400
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011401 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011402
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011403 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011404 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011405
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011406 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011407
Takashi Iwai2134ea42008-01-10 16:53:55 +010011408 spec->vmaster_nid = 0x0c;
11409
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011410 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020011411 if (board_config == ALC882_AUTO)
11412 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011413
11414 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011415#ifdef CONFIG_SND_HDA_POWER_SAVE
11416 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020011417 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011418#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011419
11420 return 0;
11421}
11422
Takashi Iwai49535502009-06-30 15:28:30 +020011423
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011424/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011425 * ALC262 support
11426 */
11427
11428#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11429#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11430
11431#define alc262_dac_nids alc260_dac_nids
11432#define alc262_adc_nids alc882_adc_nids
11433#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011434#define alc262_capsrc_nids alc882_capsrc_nids
11435#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011436
11437#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011438#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011439
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011440static const hda_nid_t alc262_dmic_adc_nids[1] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011441 /* ADC0 */
11442 0x09
11443};
11444
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011445static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
Kailang Yang4e555fe2008-08-26 13:05:55 +020011446
Takashi Iwaia9111322011-05-02 11:30:18 +020011447static const struct snd_kcontrol_new alc262_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011448 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11449 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11450 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11451 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11452 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11453 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11454 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11455 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011456 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011457 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11458 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011459 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011460 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11461 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11462 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11463 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011464 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011465};
11466
Takashi Iwaice875f02008-01-28 18:17:43 +010011467/* update HP, line and mono-out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011468#define alc262_hp_master_update alc260_hp_master_update
Takashi Iwaice875f02008-01-28 18:17:43 +010011469
Takashi Iwaie9427962011-04-28 15:46:07 +020011470static void alc262_hp_bpc_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011471{
11472 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011473
Takashi Iwaie9427962011-04-28 15:46:07 +020011474 spec->autocfg.hp_pins[0] = 0x1b;
11475 spec->autocfg.speaker_pins[0] = 0x16;
11476 spec->automute = 1;
11477 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011478}
11479
Takashi Iwaie9427962011-04-28 15:46:07 +020011480static void alc262_hp_wildwest_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011481{
11482 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011483
Takashi Iwaie9427962011-04-28 15:46:07 +020011484 spec->autocfg.hp_pins[0] = 0x15;
11485 spec->autocfg.speaker_pins[0] = 0x16;
11486 spec->automute = 1;
11487 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011488}
11489
Takashi Iwaib72519b2009-05-08 14:31:55 +020011490#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011491#define alc262_hp_master_sw_put alc260_hp_master_sw_put
Takashi Iwaice875f02008-01-28 18:17:43 +010011492
Takashi Iwaib72519b2009-05-08 14:31:55 +020011493#define ALC262_HP_MASTER_SWITCH \
11494 { \
11495 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11496 .name = "Master Playback Switch", \
11497 .info = snd_ctl_boolean_mono_info, \
11498 .get = alc262_hp_master_sw_get, \
11499 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011500 }, \
11501 { \
11502 .iface = NID_MAPPING, \
11503 .name = "Master Playback Switch", \
11504 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011505 }
11506
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011507
Takashi Iwaia9111322011-05-02 11:30:18 +020011508static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011509 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011510 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11511 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11512 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011513 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11514 HDA_OUTPUT),
11515 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11516 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011517 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11518 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011519 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011520 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11521 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011522 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011523 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11524 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11525 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11526 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011527 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11528 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11529 { } /* end */
11530};
11531
Takashi Iwaia9111322011-05-02 11:30:18 +020011532static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011533 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011534 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11535 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11536 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11537 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011538 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11539 HDA_OUTPUT),
11540 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11541 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011542 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11543 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011544 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011545 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11546 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11547 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11548 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011549 { } /* end */
11550};
11551
Takashi Iwaia9111322011-05-02 11:30:18 +020011552static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010011553 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11554 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011555 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011556 { } /* end */
11557};
11558
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011559/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011560static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011561{
11562 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011563
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011564 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011565 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020011566 spec->automute = 1;
11567 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011568}
11569
Takashi Iwaia9111322011-05-02 11:30:18 +020011570static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011571 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11572 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011573 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11574 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11575 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11576 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011577 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011578 { } /* end */
11579};
11580
Takashi Iwaia9111322011-05-02 11:30:18 +020011581static const struct hda_verb alc262_hp_t5735_verbs[] = {
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011582 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11583 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11584
11585 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11586 { }
11587};
11588
Takashi Iwaia9111322011-05-02 11:30:18 +020011589static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011590 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11591 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011592 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11593 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011594 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11595 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11596 { } /* end */
11597};
11598
Takashi Iwaia9111322011-05-02 11:30:18 +020011599static const struct hda_verb alc262_hp_rp5700_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010011600 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11601 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11602 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11603 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11604 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11605 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11606 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11607 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11608 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11609 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11610 {}
11611};
11612
Takashi Iwaia9111322011-05-02 11:30:18 +020011613static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
Kailang Yang8c427222008-01-10 13:03:59 +010011614 .num_items = 1,
11615 .items = {
11616 { "Line", 0x1 },
11617 },
11618};
11619
Takashi Iwai42171c12009-05-08 14:11:43 +020011620/* bind hp and internal speaker mute (with plug check) as master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011621#define alc262_hippo_master_update alc262_hp_master_update
Takashi Iwai42171c12009-05-08 14:11:43 +020011622#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011623#define alc262_hippo_master_sw_put alc262_hp_master_sw_put
Takashi Iwai5b319542007-07-26 11:49:22 +020011624
Takashi Iwai42171c12009-05-08 14:11:43 +020011625#define ALC262_HIPPO_MASTER_SWITCH \
11626 { \
11627 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11628 .name = "Master Playback Switch", \
11629 .info = snd_ctl_boolean_mono_info, \
11630 .get = alc262_hippo_master_sw_get, \
11631 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011632 }, \
11633 { \
11634 .iface = NID_MAPPING, \
11635 .name = "Master Playback Switch", \
11636 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11637 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011638 }
11639
Takashi Iwaia9111322011-05-02 11:30:18 +020011640static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011641 ALC262_HIPPO_MASTER_SWITCH,
11642 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11643 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11644 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11645 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11646 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11647 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11648 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011649 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011650 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11651 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011652 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011653 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11654 { } /* end */
11655};
11656
Takashi Iwaia9111322011-05-02 11:30:18 +020011657static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011658 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11659 ALC262_HIPPO_MASTER_SWITCH,
11660 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11661 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11662 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11663 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11664 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11665 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011666 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011667 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11668 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011669 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011670 { } /* end */
11671};
11672
11673/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011674static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011675{
11676 struct alc_spec *spec = codec->spec;
11677
11678 spec->autocfg.hp_pins[0] = 0x15;
11679 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011680 spec->automute = 1;
11681 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011682}
11683
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011684static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011685{
11686 struct alc_spec *spec = codec->spec;
11687
11688 spec->autocfg.hp_pins[0] = 0x1b;
11689 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011690 spec->automute = 1;
11691 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011692}
11693
11694
Takashi Iwaia9111322011-05-02 11:30:18 +020011695static const struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011696 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011697 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011698 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11699 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11700 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11701 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11702 { } /* end */
11703};
11704
Takashi Iwaia9111322011-05-02 11:30:18 +020011705static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011706 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11707 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011708 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11709 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11710 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11711 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11712 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11713 { } /* end */
11714};
Kailang Yang272a5272007-05-14 11:00:38 +020011715
Takashi Iwaia9111322011-05-02 11:30:18 +020011716static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011717 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11718 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11719 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11720 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11721 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11722 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11723 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11724 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011725 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011726 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11727 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011728 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011729 { } /* end */
11730};
11731
Takashi Iwaia9111322011-05-02 11:30:18 +020011732static const struct hda_verb alc262_tyan_verbs[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011733 /* Headphone automute */
11734 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11735 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11736 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11737
11738 /* P11 AUX_IN, white 4-pin connector */
11739 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11740 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11741 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11742 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11743
11744 {}
11745};
11746
11747/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011748static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011749{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011750 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011751
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011752 spec->autocfg.hp_pins[0] = 0x1b;
11753 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +020011754 spec->automute = 1;
11755 spec->automute_mode = ALC_AUTOMUTE_AMP;
Tony Vroonba340e82009-02-02 19:01:30 +000011756}
11757
Tony Vroonba340e82009-02-02 19:01:30 +000011758
Kailang Yangdf694da2005-12-05 19:42:22 +010011759#define alc262_capture_mixer alc882_capture_mixer
11760#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11761
11762/*
11763 * generic initialization of ADC, input mixers and output mixers
11764 */
Takashi Iwaia9111322011-05-02 11:30:18 +020011765static const struct hda_verb alc262_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011766 /*
11767 * Unmute ADC0-2 and set the default input to mic-in
11768 */
11769 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11770 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11771 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11772 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11773 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11774 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11775
Takashi Iwaicb53c622007-08-10 17:21:45 +020011776 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011777 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011778 * Note: PASD motherboards uses the Line In 2 as the input for
11779 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011780 */
11781 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011782 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11783 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11784 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11785 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11786 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011787
11788 /*
11789 * Set up output mixers (0x0c - 0x0e)
11790 */
11791 /* set vol=0 to output mixers */
11792 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11793 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11794 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11795 /* set up input amps for analog loopback */
11796 /* Amp Indices: DAC = 0, mixer = 1 */
11797 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11798 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11799 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11800 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11801 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11802 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11803
11804 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11805 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11806 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11807 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11808 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11809 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11810
11811 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11812 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11813 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11814 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11815 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011816
Kailang Yangdf694da2005-12-05 19:42:22 +010011817 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11818 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011819
Kailang Yangdf694da2005-12-05 19:42:22 +010011820 /* FIXME: use matrix-type input source selection */
11821 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11822 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11823 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11824 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11825 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11826 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11827 /* Input mixer2 */
11828 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11829 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11830 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11831 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11832 /* Input mixer3 */
11833 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11834 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11835 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011836 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011837
11838 { }
11839};
11840
Takashi Iwaia9111322011-05-02 11:30:18 +020011841static const struct hda_verb alc262_eapd_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011842 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11843 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11844 { }
11845};
11846
Takashi Iwaia9111322011-05-02 11:30:18 +020011847static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +020011848 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11849 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11850 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11851
11852 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11853 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11854 {}
11855};
11856
Takashi Iwaia9111322011-05-02 11:30:18 +020011857static const struct hda_verb alc262_sony_unsol_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020011858 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11859 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11860 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11861
11862 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11863 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011864 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011865};
11866
Takashi Iwaia9111322011-05-02 11:30:18 +020011867static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011868 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11869 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11870 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11871 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11872 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011873 { } /* end */
11874};
11875
Takashi Iwaia9111322011-05-02 11:30:18 +020011876static const struct hda_verb alc262_toshiba_s06_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011877 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11878 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11879 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11880 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11881 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11882 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11883 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11884 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11885 {}
11886};
11887
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011888static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011889{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011890 struct alc_spec *spec = codec->spec;
11891
11892 spec->autocfg.hp_pins[0] = 0x15;
11893 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011894 spec->ext_mic.pin = 0x18;
11895 spec->ext_mic.mux_idx = 0;
11896 spec->int_mic.pin = 0x12;
11897 spec->int_mic.mux_idx = 9;
11898 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020011899 spec->automute = 1;
11900 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011901}
11902
Takashi Iwai834be882006-03-01 14:16:17 +010011903/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011904 * nec model
11905 * 0x15 = headphone
11906 * 0x16 = internal speaker
11907 * 0x18 = external mic
11908 */
11909
Takashi Iwaia9111322011-05-02 11:30:18 +020011910static const struct snd_kcontrol_new alc262_nec_mixer[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011911 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11912 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11913
11914 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11915 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011916 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011917
11918 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11919 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11920 { } /* end */
11921};
11922
Takashi Iwaia9111322011-05-02 11:30:18 +020011923static const struct hda_verb alc262_nec_verbs[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011924 /* Unmute Speaker */
11925 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11926
11927 /* Headphone */
11928 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11929 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11930
11931 /* External mic to headphone */
11932 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11933 /* External mic to speaker */
11934 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11935 {}
11936};
11937
11938/*
Takashi Iwai834be882006-03-01 14:16:17 +010011939 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011940 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11941 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011942 */
11943
Takashi Iwai20f5e0b2011-06-10 09:31:54 +020011944#define ALC_HP_EVENT ALC880_HP_EVENT
Takashi Iwai834be882006-03-01 14:16:17 +010011945
Takashi Iwaia9111322011-05-02 11:30:18 +020011946static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
Takashi Iwai834be882006-03-01 14:16:17 +010011947 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11948 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011949 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11950 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011951 {}
11952};
11953
Takashi Iwaia9111322011-05-02 11:30:18 +020011954static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011955 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11956 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11957 {}
11958};
11959
Takashi Iwaia9111322011-05-02 11:30:18 +020011960static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
Daniel T Chene2595322009-12-19 18:19:02 -050011961 /* Front Mic pin: input vref at 50% */
11962 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11963 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11964 {}
11965};
11966
Takashi Iwaia9111322011-05-02 11:30:18 +020011967static const struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011968 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011969 .items = {
11970 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011971 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011972 { "CD", 0x4 },
11973 },
11974};
11975
Takashi Iwaia9111322011-05-02 11:30:18 +020011976static const struct hda_input_mux alc262_HP_capture_source = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011977 .num_items = 5,
11978 .items = {
11979 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011980 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011981 { "Line", 0x2 },
11982 { "CD", 0x4 },
11983 { "AUX IN", 0x6 },
11984 },
11985};
11986
Takashi Iwaia9111322011-05-02 11:30:18 +020011987static const struct hda_input_mux alc262_HP_D7000_capture_source = {
zhejiangaccbe492007-08-31 12:36:05 +020011988 .num_items = 4,
11989 .items = {
11990 { "Mic", 0x0 },
11991 { "Front Mic", 0x2 },
11992 { "Line", 0x1 },
11993 { "CD", 0x4 },
11994 },
11995};
11996
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011997static void alc262_fujitsu_setup(struct hda_codec *codec)
Takashi Iwai834be882006-03-01 14:16:17 +010011998{
11999 struct alc_spec *spec = codec->spec;
Takashi Iwai834be882006-03-01 14:16:17 +010012000
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012001 spec->autocfg.hp_pins[0] = 0x14;
12002 spec->autocfg.hp_pins[1] = 0x1b;
12003 spec->autocfg.speaker_pins[0] = 0x15;
12004 spec->automute = 1;
12005 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012006}
12007
Takashi Iwai834be882006-03-01 14:16:17 +010012008/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaia9111322011-05-02 11:30:18 +020012009static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020012010 .ops = &snd_hda_bind_vol,
12011 .values = {
12012 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
12013 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
12014 0
12015 },
12016};
Takashi Iwai834be882006-03-01 14:16:17 +010012017
Takashi Iwaia9111322011-05-02 11:30:18 +020012018static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020012019 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010012020 {
12021 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12022 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012023 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12024 .info = snd_ctl_boolean_mono_info,
12025 .get = alc262_hp_master_sw_get,
12026 .put = alc262_hp_master_sw_put,
Takashi Iwai834be882006-03-01 14:16:17 +010012027 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012028 {
12029 .iface = NID_MAPPING,
12030 .name = "Master Playback Switch",
12031 .private_value = 0x1b,
12032 },
Takashi Iwai834be882006-03-01 14:16:17 +010012033 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12034 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012035 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010012036 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12037 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012038 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010012039 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12040 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010012041 { } /* end */
12042};
12043
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012044static void alc262_lenovo_3000_setup(struct hda_codec *codec)
Jiang zhe0e31daf2008-03-20 12:12:39 +010012045{
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012046 struct alc_spec *spec = codec->spec;
Jiang zhe0e31daf2008-03-20 12:12:39 +010012047
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012048 spec->autocfg.hp_pins[0] = 0x1b;
12049 spec->autocfg.speaker_pins[0] = 0x14;
12050 spec->autocfg.speaker_pins[1] = 0x16;
12051 spec->automute = 1;
12052 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhe0e31daf2008-03-20 12:12:39 +010012053}
12054
Takashi Iwaia9111322011-05-02 11:30:18 +020012055static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010012056 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
12057 {
12058 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12059 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012060 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
12061 .info = snd_ctl_boolean_mono_info,
12062 .get = alc262_hp_master_sw_get,
12063 .put = alc262_hp_master_sw_put,
Jiang zhe0e31daf2008-03-20 12:12:39 +010012064 },
12065 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
12066 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012067 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012068 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12069 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012070 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010012071 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
12072 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012073 { } /* end */
12074};
12075
Takashi Iwaia9111322011-05-02 11:30:18 +020012076static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012077 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020012078 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012079 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
12080 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012081 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012082 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12083 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012084 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012085 { } /* end */
12086};
12087
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012088/* additional init verbs for Benq laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020012089static const struct hda_verb alc262_EAPD_verbs[] = {
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012090 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
12091 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
12092 {}
12093};
12094
Takashi Iwaia9111322011-05-02 11:30:18 +020012095static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
Kailang Yang83c34212007-07-05 11:43:05 +020012096 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12097 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12098
12099 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
12100 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
12101 {}
12102};
12103
Tobin Davisf651b502007-10-26 12:40:47 +020012104/* Samsung Q1 Ultra Vista model setup */
Takashi Iwaia9111322011-05-02 11:30:18 +020012105static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012106 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
12107 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020012108 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
12109 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012110 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
12111 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020012112 { } /* end */
12113};
12114
Takashi Iwaia9111322011-05-02 11:30:18 +020012115static const struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012116 /* output mixer */
12117 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12118 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12119 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12120 /* speaker */
12121 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
12122 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12123 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12124 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
12125 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020012126 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012127 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12128 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12129 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12130 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12131 /* internal mic */
12132 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12133 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12134 /* ADC, choose mic */
12135 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12136 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12137 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12138 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12139 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12140 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12141 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12142 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12143 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
12144 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020012145 {}
12146};
12147
Tobin Davisf651b502007-10-26 12:40:47 +020012148/* mute/unmute internal speaker according to the hp jack and mute state */
12149static void alc262_ultra_automute(struct hda_codec *codec)
12150{
12151 struct alc_spec *spec = codec->spec;
12152 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020012153
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012154 mute = 0;
12155 /* auto-mute only when HP is used as HP */
12156 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080012157 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012158 if (spec->jack_present)
12159 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020012160 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012161 /* mute/unmute internal speaker */
12162 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
12163 HDA_AMP_MUTE, mute);
12164 /* mute/unmute HP */
12165 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
12166 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020012167}
12168
12169/* unsolicited event for HP jack sensing */
12170static void alc262_ultra_unsol_event(struct hda_codec *codec,
12171 unsigned int res)
12172{
12173 if ((res >> 26) != ALC880_HP_EVENT)
12174 return;
12175 alc262_ultra_automute(codec);
12176}
12177
Takashi Iwaia9111322011-05-02 11:30:18 +020012178static const struct hda_input_mux alc262_ultra_capture_source = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012179 .num_items = 2,
12180 .items = {
12181 { "Mic", 0x1 },
12182 { "Headphone", 0x7 },
12183 },
12184};
12185
12186static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
12187 struct snd_ctl_elem_value *ucontrol)
12188{
12189 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
12190 struct alc_spec *spec = codec->spec;
12191 int ret;
12192
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012193 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012194 if (!ret)
12195 return 0;
12196 /* reprogram the HP pin as mic or HP according to the input source */
12197 snd_hda_codec_write_cache(codec, 0x15, 0,
12198 AC_VERB_SET_PIN_WIDGET_CONTROL,
12199 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
12200 alc262_ultra_automute(codec); /* mute/unmute HP */
12201 return ret;
12202}
12203
Takashi Iwaia9111322011-05-02 11:30:18 +020012204static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012205 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
12206 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
12207 {
12208 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12209 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012210 .info = alc_mux_enum_info,
12211 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012212 .put = alc262_ultra_mux_enum_put,
12213 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012214 {
12215 .iface = NID_MAPPING,
12216 .name = "Capture Source",
12217 .private_value = 0x15,
12218 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012219 { } /* end */
12220};
12221
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012222/* We use two mixers depending on the output pin; 0x16 is a mono output
12223 * and thus it's bound with a different mixer.
12224 * This function returns which mixer amp should be used.
12225 */
12226static int alc262_check_volbit(hda_nid_t nid)
12227{
12228 if (!nid)
12229 return 0;
12230 else if (nid == 0x16)
12231 return 2;
12232 else
12233 return 1;
12234}
12235
12236static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012237 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012238{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012239 unsigned long val;
12240 int vbit;
12241
12242 vbit = alc262_check_volbit(nid);
12243 if (!vbit)
12244 return 0;
12245 if (*vbits & vbit) /* a volume control for this mixer already there */
12246 return 0;
12247 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012248 if (vbit == 2)
12249 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
12250 else
12251 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012252 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012253}
12254
12255static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012256 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012257{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012258 unsigned long val;
12259
12260 if (!nid)
12261 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012262 if (nid == 0x16)
12263 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
12264 else
12265 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012266 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012267}
12268
Kailang Yangdf694da2005-12-05 19:42:22 +010012269/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012270static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
12271 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012272{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012273 const char *pfx;
12274 int vbits;
Takashi Iwai033688a2010-09-08 15:47:09 +020012275 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010012276
12277 spec->multiout.num_dacs = 1; /* only use one dac */
12278 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +020012279 spec->private_dac_nids[0] = 2;
Kailang Yangdf694da2005-12-05 19:42:22 +010012280
Takashi Iwaice764ab2011-04-27 16:35:23 +020012281 pfx = alc_get_line_out_pfx(spec, true);
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010012282 if (!pfx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012283 pfx = "Front";
Takashi Iwai033688a2010-09-08 15:47:09 +020012284 for (i = 0; i < 2; i++) {
12285 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
12286 if (err < 0)
12287 return err;
12288 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12289 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
12290 "Speaker", i);
12291 if (err < 0)
12292 return err;
12293 }
12294 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12295 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
12296 "Headphone", i);
12297 if (err < 0)
12298 return err;
12299 }
12300 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012301
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012302 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
12303 alc262_check_volbit(cfg->speaker_pins[0]) |
12304 alc262_check_volbit(cfg->hp_pins[0]);
12305 if (vbits == 1 || vbits == 2)
12306 pfx = "Master"; /* only one mixer is used */
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012307 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020012308 for (i = 0; i < 2; i++) {
12309 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
12310 &vbits, i);
12311 if (err < 0)
12312 return err;
12313 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12314 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
12315 "Speaker", &vbits, i);
12316 if (err < 0)
12317 return err;
12318 }
12319 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12320 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
12321 "Headphone", &vbits, i);
12322 if (err < 0)
12323 return err;
12324 }
12325 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012326 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010012327}
12328
Takashi Iwai05f5f472009-08-25 13:10:18 +020012329#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010012330 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010012331
12332/*
12333 * generic initialization of ADC, input mixers and output mixers
12334 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012335static const struct hda_verb alc262_volume_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010012336 /*
12337 * Unmute ADC0-2 and set the default input to mic-in
12338 */
12339 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12340 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12341 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12342 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12343 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12344 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12345
Takashi Iwaicb53c622007-08-10 17:21:45 +020012346 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010012347 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012348 * Note: PASD motherboards uses the Line In 2 as the input for
12349 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010012350 */
12351 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012352 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12353 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12354 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12355 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12356 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012357
12358 /*
12359 * Set up output mixers (0x0c - 0x0f)
12360 */
12361 /* set vol=0 to output mixers */
12362 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12363 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12364 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020012365
Kailang Yangdf694da2005-12-05 19:42:22 +010012366 /* set up input amps for analog loopback */
12367 /* Amp Indices: DAC = 0, mixer = 1 */
12368 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12369 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12370 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12371 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12372 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12373 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12374
12375 /* FIXME: use matrix-type input source selection */
12376 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12377 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12378 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12379 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12380 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12381 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12382 /* Input mixer2 */
12383 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12384 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12385 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12386 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12387 /* Input mixer3 */
12388 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12389 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12390 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12391 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12392
12393 { }
12394};
12395
Takashi Iwaia9111322011-05-02 11:30:18 +020012396static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012397 /*
12398 * Unmute ADC0-2 and set the default input to mic-in
12399 */
12400 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12401 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12402 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12403 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12404 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12405 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12406
Takashi Iwaicb53c622007-08-10 17:21:45 +020012407 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012408 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012409 * Note: PASD motherboards uses the Line In 2 as the input for
12410 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012411 */
12412 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012413 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12414 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12415 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12416 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12417 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12418 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12419 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012420
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012421 /*
12422 * Set up output mixers (0x0c - 0x0e)
12423 */
12424 /* set vol=0 to output mixers */
12425 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12426 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12427 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12428
12429 /* set up input amps for analog loopback */
12430 /* Amp Indices: DAC = 0, mixer = 1 */
12431 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12432 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12433 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12434 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12435 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12436 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12437
Takashi Iwaice875f02008-01-28 18:17:43 +010012438 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012439 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12440 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12441
12442 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12443 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12444
12445 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12446 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12447
12448 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12449 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12450 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12451 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12452 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12453
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012454 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012455 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12456 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012457 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012458 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12459 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12460
12461
12462 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012463 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12464 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012465 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012466 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12467 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12468 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12469 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12470 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12471 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12472 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12473 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012474 /* Input mixer2 */
12475 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012476 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12477 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12478 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12479 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12480 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12481 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12482 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12483 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012484 /* Input mixer3 */
12485 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012486 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12487 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12488 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12489 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12490 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12491 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12492 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12493 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012494
Takashi Iwaice875f02008-01-28 18:17:43 +010012495 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12496
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012497 { }
12498};
12499
Takashi Iwaia9111322011-05-02 11:30:18 +020012500static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010012501 /*
12502 * Unmute ADC0-2 and set the default input to mic-in
12503 */
12504 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12505 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12506 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12507 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12508 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12509 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12510
Takashi Iwaicb53c622007-08-10 17:21:45 +020012511 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012512 * mixer widget
12513 * Note: PASD motherboards uses the Line In 2 as the input for front
12514 * panel mic (mic 2)
12515 */
12516 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012517 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12518 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12519 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12520 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12521 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12522 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12523 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12524 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012525 /*
12526 * Set up output mixers (0x0c - 0x0e)
12527 */
12528 /* set vol=0 to output mixers */
12529 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12530 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12531 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12532
12533 /* set up input amps for analog loopback */
12534 /* Amp Indices: DAC = 0, mixer = 1 */
12535 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12536 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12537 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12538 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12539 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12540 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12541
12542
12543 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12544 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12545 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12546 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12547 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12548 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12549 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12550
12551 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12552 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12553
12554 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12555 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12556
12557 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12558 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12559 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12560 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12561 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12562 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12563
12564 /* FIXME: use matrix-type input source selection */
12565 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12566 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12567 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12568 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12569 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12570 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12571 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12572 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12573 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12574 /* Input mixer2 */
12575 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12576 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12577 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12578 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12579 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12580 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12581 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12582 /* Input mixer3 */
12583 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12584 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12585 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12586 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12587 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12588 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12589 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12590
Takashi Iwaice875f02008-01-28 18:17:43 +010012591 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12592
Kailang Yangcd7509a2007-01-26 18:33:17 +010012593 { }
12594};
12595
Takashi Iwaia9111322011-05-02 11:30:18 +020012596static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012597
12598 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12599 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12600 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12601
12602 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12603 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12604 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12605 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12606
12607 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12608 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12609 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12610 {}
12611};
12612
Takashi Iwai18675e42010-09-08 15:55:44 +020012613/*
12614 * Pin config fixes
12615 */
12616enum {
12617 PINFIX_FSC_H270,
David Henningssond2a19da2011-06-22 09:58:37 +020012618 PINFIX_HP_Z200,
Takashi Iwai18675e42010-09-08 15:55:44 +020012619};
12620
12621static const struct alc_fixup alc262_fixups[] = {
12622 [PINFIX_FSC_H270] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012623 .type = ALC_FIXUP_PINS,
12624 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai18675e42010-09-08 15:55:44 +020012625 { 0x14, 0x99130110 }, /* speaker */
12626 { 0x15, 0x0221142f }, /* front HP */
12627 { 0x1b, 0x0121141f }, /* rear HP */
12628 { }
12629 }
12630 },
David Henningssond2a19da2011-06-22 09:58:37 +020012631 [PINFIX_HP_Z200] = {
12632 .type = ALC_FIXUP_PINS,
12633 .v.pins = (const struct alc_pincfg[]) {
12634 { 0x16, 0x99130120 }, /* internal speaker */
12635 { }
12636 }
12637 },
Takashi Iwai18675e42010-09-08 15:55:44 +020012638};
12639
Takashi Iwaia9111322011-05-02 11:30:18 +020012640static const struct snd_pci_quirk alc262_fixup_tbl[] = {
David Henningssond2a19da2011-06-22 09:58:37 +020012641 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
Takashi Iwai18675e42010-09-08 15:55:44 +020012642 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12643 {}
12644};
12645
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012646
Takashi Iwaicb53c622007-08-10 17:21:45 +020012647#ifdef CONFIG_SND_HDA_POWER_SAVE
12648#define alc262_loopbacks alc880_loopbacks
12649#endif
12650
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012651/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012652#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12653#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12654#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12655#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12656
12657/*
12658 * BIOS auto configuration
12659 */
12660static int alc262_parse_auto_config(struct hda_codec *codec)
12661{
12662 struct alc_spec *spec = codec->spec;
12663 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012664 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012665
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012666 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12667 alc262_ignore);
12668 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012669 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012670 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012671 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012672 spec->multiout.max_channels = 2;
12673 spec->no_analog = 1;
12674 goto dig_only;
12675 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012676 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012677 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012678 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12679 if (err < 0)
12680 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012681 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012682 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012683 return err;
12684
12685 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12686
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012687 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012688 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012689
Takashi Iwai603c4012008-07-30 15:01:44 +020012690 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012691 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012692
Takashi Iwaid88897e2008-10-31 15:01:37 +010012693 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012694 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012695 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012696
Takashi Iwai776e1842007-08-29 15:07:11 +020012697 err = alc_auto_add_mic_boost(codec);
12698 if (err < 0)
12699 return err;
12700
Kailang Yang6227cdc2010-02-25 08:36:52 +010012701 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012702
Kailang Yangdf694da2005-12-05 19:42:22 +010012703 return 1;
12704}
12705
12706#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12707#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12708#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012709#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012710
12711
12712/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012713static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012714{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012715 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012716 alc262_auto_init_multi_out(codec);
12717 alc262_auto_init_hp_out(codec);
12718 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012719 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012720 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012721 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012722 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012723}
12724
12725/*
12726 * configuration and preset
12727 */
Takashi Iwaiea734962011-01-17 11:29:34 +010012728static const char * const alc262_models[ALC262_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012729 [ALC262_BASIC] = "basic",
12730 [ALC262_HIPPO] = "hippo",
12731 [ALC262_HIPPO_1] = "hippo_1",
12732 [ALC262_FUJITSU] = "fujitsu",
12733 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012734 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012735 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012736 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012737 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012738 [ALC262_BENQ_T31] = "benq-t31",
12739 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012740 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012741 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012742 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012743 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012744 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012745 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012746 [ALC262_AUTO] = "auto",
12747};
12748
Takashi Iwaia9111322011-05-02 11:30:18 +020012749static const struct snd_pci_quirk alc262_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012750 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012751 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012752 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12753 ALC262_HP_BPC),
12754 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12755 ALC262_HP_BPC),
Takashi Iwai5734a072011-01-19 17:07:12 +010012756 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
12757 ALC262_HP_BPC),
David Henningssond2a19da2011-06-22 09:58:37 +020012758 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
12759 ALC262_AUTO),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012760 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12761 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012762 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012763 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012764 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012765 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012766 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012767 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012768 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012769 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012770 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12771 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12772 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012773 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12774 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012775 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012776 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012777 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012778 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012779 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012780 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012781 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012782 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012783#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012784 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12785 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012786#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012787 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012788 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012789 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012790 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012791 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012792 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012793 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12794 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012795 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012796 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012797 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012798 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012799 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012800 {}
12801};
12802
Takashi Iwaia9111322011-05-02 11:30:18 +020012803static const struct alc_config_preset alc262_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010012804 [ALC262_BASIC] = {
12805 .mixers = { alc262_base_mixer },
12806 .init_verbs = { alc262_init_verbs },
12807 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12808 .dac_nids = alc262_dac_nids,
12809 .hp_nid = 0x03,
12810 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12811 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012812 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012813 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012814 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012815 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012816 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012817 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12818 .dac_nids = alc262_dac_nids,
12819 .hp_nid = 0x03,
12820 .dig_out_nid = ALC262_DIGOUT_NID,
12821 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12822 .channel_mode = alc262_modes,
12823 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012824 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012825 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012826 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012827 },
12828 [ALC262_HIPPO_1] = {
12829 .mixers = { alc262_hippo1_mixer },
12830 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12831 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12832 .dac_nids = alc262_dac_nids,
12833 .hp_nid = 0x02,
12834 .dig_out_nid = ALC262_DIGOUT_NID,
12835 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12836 .channel_mode = alc262_modes,
12837 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012838 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012839 .setup = alc262_hippo1_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012840 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012841 },
Takashi Iwai834be882006-03-01 14:16:17 +010012842 [ALC262_FUJITSU] = {
12843 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012844 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12845 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012846 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12847 .dac_nids = alc262_dac_nids,
12848 .hp_nid = 0x03,
12849 .dig_out_nid = ALC262_DIGOUT_NID,
12850 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12851 .channel_mode = alc262_modes,
12852 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012853 .unsol_event = alc_sku_unsol_event,
12854 .setup = alc262_fujitsu_setup,
12855 .init_hook = alc_inithook,
Takashi Iwai834be882006-03-01 14:16:17 +010012856 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012857 [ALC262_HP_BPC] = {
12858 .mixers = { alc262_HP_BPC_mixer },
12859 .init_verbs = { alc262_HP_BPC_init_verbs },
12860 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12861 .dac_nids = alc262_dac_nids,
12862 .hp_nid = 0x03,
12863 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12864 .channel_mode = alc262_modes,
12865 .input_mux = &alc262_HP_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012866 .unsol_event = alc_sku_unsol_event,
12867 .setup = alc262_hp_bpc_setup,
12868 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012869 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012870 [ALC262_HP_BPC_D7000_WF] = {
12871 .mixers = { alc262_HP_BPC_WildWest_mixer },
12872 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12873 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12874 .dac_nids = alc262_dac_nids,
12875 .hp_nid = 0x03,
12876 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12877 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012878 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012879 .unsol_event = alc_sku_unsol_event,
12880 .setup = alc262_hp_wildwest_setup,
12881 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012882 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012883 [ALC262_HP_BPC_D7000_WL] = {
12884 .mixers = { alc262_HP_BPC_WildWest_mixer,
12885 alc262_HP_BPC_WildWest_option_mixer },
12886 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12887 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12888 .dac_nids = alc262_dac_nids,
12889 .hp_nid = 0x03,
12890 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12891 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012892 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012893 .unsol_event = alc_sku_unsol_event,
12894 .setup = alc262_hp_wildwest_setup,
12895 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012896 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012897 [ALC262_HP_TC_T5735] = {
12898 .mixers = { alc262_hp_t5735_mixer },
12899 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12900 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12901 .dac_nids = alc262_dac_nids,
12902 .hp_nid = 0x03,
12903 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12904 .channel_mode = alc262_modes,
12905 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012906 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012907 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012908 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012909 },
12910 [ALC262_HP_RP5700] = {
12911 .mixers = { alc262_hp_rp5700_mixer },
12912 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12913 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12914 .dac_nids = alc262_dac_nids,
12915 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12916 .channel_mode = alc262_modes,
12917 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012918 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012919 [ALC262_BENQ_ED8] = {
12920 .mixers = { alc262_base_mixer },
12921 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12922 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12923 .dac_nids = alc262_dac_nids,
12924 .hp_nid = 0x03,
12925 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12926 .channel_mode = alc262_modes,
12927 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012928 },
Kailang Yang272a5272007-05-14 11:00:38 +020012929 [ALC262_SONY_ASSAMD] = {
12930 .mixers = { alc262_sony_mixer },
12931 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12932 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12933 .dac_nids = alc262_dac_nids,
12934 .hp_nid = 0x02,
12935 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12936 .channel_mode = alc262_modes,
12937 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012938 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012939 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012940 .init_hook = alc_inithook,
Kailang Yang83c34212007-07-05 11:43:05 +020012941 },
12942 [ALC262_BENQ_T31] = {
12943 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012944 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12945 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012946 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12947 .dac_nids = alc262_dac_nids,
12948 .hp_nid = 0x03,
12949 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12950 .channel_mode = alc262_modes,
12951 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012952 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012953 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012954 .init_hook = alc_inithook,
Kailang Yangea1fb292008-08-26 12:58:38 +020012955 },
Tobin Davisf651b502007-10-26 12:40:47 +020012956 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012957 .mixers = { alc262_ultra_mixer },
12958 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012959 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012960 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12961 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012962 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12963 .channel_mode = alc262_modes,
12964 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012965 .adc_nids = alc262_adc_nids, /* ADC0 */
12966 .capsrc_nids = alc262_capsrc_nids,
12967 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012968 .unsol_event = alc262_ultra_unsol_event,
12969 .init_hook = alc262_ultra_automute,
12970 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012971 [ALC262_LENOVO_3000] = {
12972 .mixers = { alc262_lenovo_3000_mixer },
12973 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012974 alc262_lenovo_3000_unsol_verbs,
12975 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012976 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12977 .dac_nids = alc262_dac_nids,
12978 .hp_nid = 0x03,
12979 .dig_out_nid = ALC262_DIGOUT_NID,
12980 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12981 .channel_mode = alc262_modes,
12982 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012983 .unsol_event = alc_sku_unsol_event,
12984 .setup = alc262_lenovo_3000_setup,
12985 .init_hook = alc_inithook,
Jiang zhe0e31daf2008-03-20 12:12:39 +010012986 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012987 [ALC262_NEC] = {
12988 .mixers = { alc262_nec_mixer },
12989 .init_verbs = { alc262_nec_verbs },
12990 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12991 .dac_nids = alc262_dac_nids,
12992 .hp_nid = 0x03,
12993 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12994 .channel_mode = alc262_modes,
12995 .input_mux = &alc262_capture_source,
12996 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012997 [ALC262_TOSHIBA_S06] = {
12998 .mixers = { alc262_toshiba_s06_mixer },
12999 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
13000 alc262_eapd_verbs },
13001 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
13002 .capsrc_nids = alc262_dmic_capsrc_nids,
13003 .dac_nids = alc262_dac_nids,
13004 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020013005 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020013006 .dig_out_nid = ALC262_DIGOUT_NID,
13007 .num_channel_mode = ARRAY_SIZE(alc262_modes),
13008 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013009 .unsol_event = alc_sku_unsol_event,
13010 .setup = alc262_toshiba_s06_setup,
13011 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020013012 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020013013 [ALC262_TOSHIBA_RX1] = {
13014 .mixers = { alc262_toshiba_rx1_mixer },
13015 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
13016 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
13017 .dac_nids = alc262_dac_nids,
13018 .hp_nid = 0x03,
13019 .num_channel_mode = ARRAY_SIZE(alc262_modes),
13020 .channel_mode = alc262_modes,
13021 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013022 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013023 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013024 .init_hook = alc_inithook,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020013025 },
Tony Vroonba340e82009-02-02 19:01:30 +000013026 [ALC262_TYAN] = {
13027 .mixers = { alc262_tyan_mixer },
13028 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
13029 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
13030 .dac_nids = alc262_dac_nids,
13031 .hp_nid = 0x02,
13032 .dig_out_nid = ALC262_DIGOUT_NID,
13033 .num_channel_mode = ARRAY_SIZE(alc262_modes),
13034 .channel_mode = alc262_modes,
13035 .input_mux = &alc262_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020013036 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013037 .setup = alc262_tyan_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020013038 .init_hook = alc_hp_automute,
Tony Vroonba340e82009-02-02 19:01:30 +000013039 },
Kailang Yangdf694da2005-12-05 19:42:22 +010013040};
13041
13042static int patch_alc262(struct hda_codec *codec)
13043{
13044 struct alc_spec *spec;
13045 int board_config;
13046 int err;
13047
Robert P. J. Daydc041e02006-12-19 14:44:15 +010013048 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010013049 if (spec == NULL)
13050 return -ENOMEM;
13051
13052 codec->spec = spec;
13053#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013054 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
13055 * under-run
13056 */
Kailang Yangdf694da2005-12-05 19:42:22 +010013057 {
13058 int tmp;
13059 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
13060 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
13061 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
13062 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
13063 }
13064#endif
Kailang Yangda00c242010-03-19 11:23:45 +010013065 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010013066
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020013067 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
13068
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013069 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
13070 alc262_models,
13071 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010013072
Takashi Iwaif5fcc132006-11-24 17:07:44 +010013073 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013074 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13075 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010013076 board_config = ALC262_AUTO;
13077 }
13078
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010013079 if (board_config == ALC262_AUTO) {
13080 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
13081 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
13082 }
Takashi Iwai18675e42010-09-08 15:55:44 +020013083
Kailang Yangdf694da2005-12-05 19:42:22 +010013084 if (board_config == ALC262_AUTO) {
13085 /* automatic parse from the BIOS config */
13086 err = alc262_parse_auto_config(codec);
13087 if (err < 0) {
13088 alc_free(codec);
13089 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013090 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020013091 printk(KERN_INFO
13092 "hda_codec: Cannot set up configuration "
13093 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010013094 board_config = ALC262_BASIC;
13095 }
13096 }
13097
Takashi Iwaidc1eae22010-07-29 15:30:02 +020013098 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010013099 err = snd_hda_attach_beep_device(codec, 0x1);
13100 if (err < 0) {
13101 alc_free(codec);
13102 return err;
13103 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090013104 }
13105
Kailang Yangdf694da2005-12-05 19:42:22 +010013106 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013107 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010013108
Kailang Yangdf694da2005-12-05 19:42:22 +010013109 spec->stream_analog_playback = &alc262_pcm_analog_playback;
13110 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020013111
Kailang Yangdf694da2005-12-05 19:42:22 +010013112 spec->stream_digital_playback = &alc262_pcm_digital_playback;
13113 spec->stream_digital_capture = &alc262_pcm_digital_capture;
13114
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020013115 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020013116 int i;
13117 /* check whether the digital-mic has to be supported */
13118 for (i = 0; i < spec->input_mux->num_items; i++) {
13119 if (spec->input_mux->items[i].index >= 9)
13120 break;
13121 }
13122 if (i < spec->input_mux->num_items) {
13123 /* use only ADC0 */
13124 spec->adc_nids = alc262_dmic_adc_nids;
13125 spec->num_adc_nids = 1;
13126 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010013127 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020013128 /* all analog inputs */
13129 /* check whether NID 0x07 is valid */
13130 unsigned int wcap = get_wcaps(codec, 0x07);
13131
13132 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020013133 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020013134 if (wcap != AC_WID_AUD_IN) {
13135 spec->adc_nids = alc262_adc_nids_alt;
13136 spec->num_adc_nids =
13137 ARRAY_SIZE(alc262_adc_nids_alt);
13138 spec->capsrc_nids = alc262_capsrc_nids_alt;
13139 } else {
13140 spec->adc_nids = alc262_adc_nids;
13141 spec->num_adc_nids =
13142 ARRAY_SIZE(alc262_adc_nids);
13143 spec->capsrc_nids = alc262_capsrc_nids;
13144 }
Kailang Yangdf694da2005-12-05 19:42:22 +010013145 }
13146 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010013147 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020013148 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020013149 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010013150 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010013151
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010013152 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai18675e42010-09-08 15:55:44 +020013153
Takashi Iwai2134ea42008-01-10 16:53:55 +010013154 spec->vmaster_nid = 0x0c;
13155
Kailang Yangdf694da2005-12-05 19:42:22 +010013156 codec->patch_ops = alc_patch_ops;
13157 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010013158 spec->init_hook = alc262_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020013159 spec->shutup = alc_eapd_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020013160
13161 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020013162#ifdef CONFIG_SND_HDA_POWER_SAVE
13163 if (!spec->loopback.amplist)
13164 spec->loopback.amplist = alc262_loopbacks;
13165#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020013166
Kailang Yangdf694da2005-12-05 19:42:22 +010013167 return 0;
13168}
13169
Kailang Yangdf694da2005-12-05 19:42:22 +010013170/*
Kailang Yanga361d842007-06-05 12:30:55 +020013171 * ALC268 channel source setting (2 channel)
13172 */
13173#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
13174#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020013175
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013176static const hda_nid_t alc268_dac_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013177 /* front, hp */
13178 0x02, 0x03
13179};
13180
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013181static const hda_nid_t alc268_adc_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013182 /* ADC0-1 */
13183 0x08, 0x07
13184};
13185
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013186static const hda_nid_t alc268_adc_nids_alt[1] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013187 /* ADC0 */
13188 0x08
13189};
13190
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013191static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
Takashi Iwaie1406342008-02-11 18:32:32 +010013192
Takashi Iwaia9111322011-05-02 11:30:18 +020013193static const struct snd_kcontrol_new alc268_base_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013194 /* output mixer control */
13195 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13196 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13197 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13198 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013199 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13200 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13201 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020013202 { }
13203};
13204
Takashi Iwaia9111322011-05-02 11:30:18 +020013205static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013206 /* output mixer control */
13207 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13208 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13209 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010013210 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13211 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13212 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020013213 { }
13214};
13215
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013216/* bind Beep switches of both NID 0x0f and 0x10 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013217static const struct hda_bind_ctls alc268_bind_beep_sw = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013218 .ops = &snd_hda_bind_sw,
13219 .values = {
13220 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
13221 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
13222 0
13223 },
13224};
13225
Takashi Iwaia9111322011-05-02 11:30:18 +020013226static const struct snd_kcontrol_new alc268_beep_mixer[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013227 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
13228 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
13229 { }
13230};
13231
Takashi Iwaia9111322011-05-02 11:30:18 +020013232static const struct hda_verb alc268_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020013233 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13234 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13235 { }
13236};
13237
Takashi Iwaid2738092007-08-16 14:59:45 +020013238/* Toshiba specific */
Takashi Iwaia9111322011-05-02 11:30:18 +020013239static const struct hda_verb alc268_toshiba_verbs[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020013240 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13241 { } /* end */
13242};
13243
13244/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020013245/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013246static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
Takashi Iwai6bc96852007-08-17 09:02:12 +020013247 .ops = &snd_hda_bind_vol,
13248 .values = {
13249 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
13250 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
13251 0
13252 },
13253};
13254
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013255static void alc268_acer_setup(struct hda_codec *codec)
Takashi Iwai889c4392007-08-23 18:56:52 +020013256{
13257 struct alc_spec *spec = codec->spec;
Takashi Iwai889c4392007-08-23 18:56:52 +020013258
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013259 spec->autocfg.hp_pins[0] = 0x14;
13260 spec->autocfg.speaker_pins[0] = 0x15;
13261 spec->automute = 1;
13262 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai889c4392007-08-23 18:56:52 +020013263}
13264
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013265#define alc268_acer_master_sw_get alc262_hp_master_sw_get
13266#define alc268_acer_master_sw_put alc262_hp_master_sw_put
Takashi Iwaid2738092007-08-16 14:59:45 +020013267
Takashi Iwaia9111322011-05-02 11:30:18 +020013268static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020013269 /* output mixer control */
13270 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13271 {
13272 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13273 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013274 .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
13275 .info = snd_ctl_boolean_mono_info,
13276 .get = alc268_acer_master_sw_get,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013277 .put = alc268_acer_master_sw_put,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013278 },
13279 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
13280 { }
13281};
13282
Takashi Iwaia9111322011-05-02 11:30:18 +020013283static const struct snd_kcontrol_new alc268_acer_mixer[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020013284 /* output mixer control */
13285 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13286 {
13287 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13288 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013289 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
13290 .info = snd_ctl_boolean_mono_info,
13291 .get = alc268_acer_master_sw_get,
Takashi Iwaid2738092007-08-16 14:59:45 +020013292 .put = alc268_acer_master_sw_put,
Takashi Iwaid2738092007-08-16 14:59:45 +020013293 },
David Henningsson5f99f862011-01-04 15:24:24 +010013294 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13295 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
13296 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020013297 { }
13298};
13299
Takashi Iwaia9111322011-05-02 11:30:18 +020013300static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013301 /* output mixer control */
13302 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13303 {
13304 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13305 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013306 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
13307 .info = snd_ctl_boolean_mono_info,
13308 .get = alc268_acer_master_sw_get,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013309 .put = alc268_acer_master_sw_put,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013310 },
David Henningsson5f99f862011-01-04 15:24:24 +010013311 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13312 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013313 { }
13314};
13315
Takashi Iwaia9111322011-05-02 11:30:18 +020013316static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020013317 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13318 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13319 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13320 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13321 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
13322 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
13323 { }
13324};
13325
Takashi Iwaia9111322011-05-02 11:30:18 +020013326static const struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013327 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
13328 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020013329 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13330 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013331 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13332 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020013333 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13334 { }
13335};
13336
13337/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013338#define alc268_toshiba_setup alc262_hippo_setup
Takashi Iwaid2738092007-08-16 14:59:45 +020013339
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013340static void alc268_acer_lc_setup(struct hda_codec *codec)
13341{
13342 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013343 spec->autocfg.hp_pins[0] = 0x15;
13344 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013345 spec->automute = 1;
Takashi Iwai54463a62011-06-13 08:32:06 +020013346 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013347 spec->ext_mic.pin = 0x18;
13348 spec->ext_mic.mux_idx = 0;
13349 spec->int_mic.pin = 0x12;
13350 spec->int_mic.mux_idx = 6;
13351 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013352}
13353
Takashi Iwaia9111322011-05-02 11:30:18 +020013354static const struct snd_kcontrol_new alc268_dell_mixer[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013355 /* output mixer control */
13356 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13357 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13358 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13359 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013360 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13361 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013362 { }
13363};
13364
Takashi Iwaia9111322011-05-02 11:30:18 +020013365static const struct hda_verb alc268_dell_verbs[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013366 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13367 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13368 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013369 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013370 { }
13371};
13372
13373/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013374static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013375{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013376 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013377
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013378 spec->autocfg.hp_pins[0] = 0x15;
13379 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013380 spec->ext_mic.pin = 0x18;
13381 spec->ext_mic.mux_idx = 0;
13382 spec->int_mic.pin = 0x19;
13383 spec->int_mic.mux_idx = 1;
13384 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020013385 spec->automute = 1;
13386 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013387}
13388
Takashi Iwaia9111322011-05-02 11:30:18 +020013389static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013390 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13391 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13392 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13393 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13394 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13395 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013396 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13397 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013398 { }
13399};
13400
Takashi Iwaia9111322011-05-02 11:30:18 +020013401static const struct hda_verb alc267_quanta_il1_verbs[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013402 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13403 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
13404 { }
13405};
13406
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013407static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013408{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013409 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013410 spec->autocfg.hp_pins[0] = 0x15;
13411 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013412 spec->ext_mic.pin = 0x18;
13413 spec->ext_mic.mux_idx = 0;
13414 spec->int_mic.pin = 0x19;
13415 spec->int_mic.mux_idx = 1;
13416 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020013417 spec->automute = 1;
13418 spec->automute_mode = ALC_AUTOMUTE_PIN;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013419}
13420
Kailang Yanga361d842007-06-05 12:30:55 +020013421/*
13422 * generic initialization of ADC, input mixers and output mixers
13423 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013424static const struct hda_verb alc268_base_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013425 /* Unmute DAC0-1 and set vol = 0 */
13426 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013427 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013428
13429 /*
13430 * Set up output mixers (0x0c - 0x0e)
13431 */
13432 /* set vol=0 to output mixers */
13433 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013434 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13435
13436 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13437 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13438
13439 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13440 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13441 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13442 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13443 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13444 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13445 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13446 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13447
13448 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13449 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13450 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13451 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013452 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013453
13454 /* set PCBEEP vol = 0, mute connections */
13455 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13456 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13457 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013458
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013459 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013460
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013461 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13462 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13463 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13464 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013465
Kailang Yanga361d842007-06-05 12:30:55 +020013466 { }
13467};
13468
13469/*
13470 * generic initialization of ADC, input mixers and output mixers
13471 */
Takashi Iwaia9111322011-05-02 11:30:18 +020013472static const struct hda_verb alc268_volume_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013473 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013474 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13475 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013476
13477 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13478 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13479 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13480 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13481 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13482
Kailang Yanga361d842007-06-05 12:30:55 +020013483 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013484 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13485 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13486
13487 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013488 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013489
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013490 /* set PCBEEP vol = 0, mute connections */
13491 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13492 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13493 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013494
13495 { }
13496};
13497
Takashi Iwaia9111322011-05-02 11:30:18 +020013498static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013499 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13500 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13501 { } /* end */
13502};
13503
Takashi Iwaia9111322011-05-02 11:30:18 +020013504static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013505 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13506 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013507 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013508 { } /* end */
13509};
13510
Takashi Iwaia9111322011-05-02 11:30:18 +020013511static const struct snd_kcontrol_new alc268_capture_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013512 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13513 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13514 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13515 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013516 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013517 { } /* end */
13518};
13519
Takashi Iwaia9111322011-05-02 11:30:18 +020013520static const struct hda_input_mux alc268_capture_source = {
Kailang Yanga361d842007-06-05 12:30:55 +020013521 .num_items = 4,
13522 .items = {
13523 { "Mic", 0x0 },
13524 { "Front Mic", 0x1 },
13525 { "Line", 0x2 },
13526 { "CD", 0x3 },
13527 },
13528};
13529
Takashi Iwaia9111322011-05-02 11:30:18 +020013530static const struct hda_input_mux alc268_acer_capture_source = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013531 .num_items = 3,
13532 .items = {
13533 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013534 { "Internal Mic", 0x1 },
13535 { "Line", 0x2 },
13536 },
13537};
13538
Takashi Iwaia9111322011-05-02 11:30:18 +020013539static const struct hda_input_mux alc268_acer_dmic_capture_source = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013540 .num_items = 3,
13541 .items = {
13542 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013543 { "Internal Mic", 0x6 },
13544 { "Line", 0x2 },
13545 },
13546};
13547
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013548#ifdef CONFIG_SND_DEBUG
Takashi Iwaia9111322011-05-02 11:30:18 +020013549static const struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013550 /* Volume widgets */
13551 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13552 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13553 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13554 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13555 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13556 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13557 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13558 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13559 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13560 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13561 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13562 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13563 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013564 /* The below appears problematic on some hardwares */
13565 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013566 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13567 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13568 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13569 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13570
13571 /* Modes for retasking pin widgets */
13572 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13573 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13574 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13575 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13576
13577 /* Controls for GPIO pins, assuming they are configured as outputs */
13578 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13579 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13580 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13581 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13582
13583 /* Switches to allow the digital SPDIF output pin to be enabled.
13584 * The ALC268 does not have an SPDIF input.
13585 */
13586 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13587
13588 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13589 * this output to turn on an external amplifier.
13590 */
13591 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13592 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13593
13594 { } /* end */
13595};
13596#endif
13597
Kailang Yanga361d842007-06-05 12:30:55 +020013598/* create input playback/capture controls for the given pin */
13599static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13600 const char *ctlname, int idx)
13601{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013602 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013603 int err;
13604
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013605 switch (nid) {
13606 case 0x14:
13607 case 0x16:
13608 dac = 0x02;
13609 break;
13610 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013611 case 0x1a: /* ALC259/269 only */
13612 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013613 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013614 dac = 0x03;
13615 break;
13616 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013617 snd_printd(KERN_WARNING "hda_codec: "
13618 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013619 return 0;
13620 }
13621 if (spec->multiout.dac_nids[0] != dac &&
13622 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013623 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013624 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013625 HDA_OUTPUT));
13626 if (err < 0)
13627 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020013628 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013629 }
13630
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013631 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013632 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013633 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013634 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013635 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013636 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013637 if (err < 0)
13638 return err;
13639 return 0;
13640}
13641
13642/* add playback controls from the parsed DAC table */
13643static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13644 const struct auto_pin_cfg *cfg)
13645{
13646 hda_nid_t nid;
13647 int err;
13648
Kailang Yanga361d842007-06-05 12:30:55 +020013649 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013650
13651 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013652 if (nid) {
13653 const char *name;
13654 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13655 name = "Speaker";
13656 else
13657 name = "Front";
13658 err = alc268_new_analog_output(spec, nid, name, 0);
13659 if (err < 0)
13660 return err;
13661 }
Kailang Yanga361d842007-06-05 12:30:55 +020013662
13663 nid = cfg->speaker_pins[0];
13664 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013665 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013666 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13667 if (err < 0)
13668 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013669 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013670 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13671 if (err < 0)
13672 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013673 }
13674 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013675 if (nid) {
13676 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13677 if (err < 0)
13678 return err;
13679 }
Kailang Yanga361d842007-06-05 12:30:55 +020013680
13681 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13682 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013683 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013684 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013685 if (err < 0)
13686 return err;
13687 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013688 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013689}
13690
13691/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013692static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013693 const struct auto_pin_cfg *cfg)
13694{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013695 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013696}
13697
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013698static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13699 hda_nid_t nid, int pin_type)
13700{
13701 int idx;
13702
13703 alc_set_pin_output(codec, nid, pin_type);
13704 if (nid == 0x14 || nid == 0x16)
13705 idx = 0;
13706 else
13707 idx = 1;
13708 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13709}
13710
13711static void alc268_auto_init_multi_out(struct hda_codec *codec)
13712{
13713 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013714 int i;
13715
13716 for (i = 0; i < spec->autocfg.line_outs; i++) {
13717 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013718 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13719 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13720 }
13721}
13722
13723static void alc268_auto_init_hp_out(struct hda_codec *codec)
13724{
13725 struct alc_spec *spec = codec->spec;
13726 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013727 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013728
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013729 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13730 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013731 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013732 }
13733 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13734 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013735 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013736 }
13737 if (spec->autocfg.mono_out_pin)
13738 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13739 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013740}
13741
Kailang Yanga361d842007-06-05 12:30:55 +020013742static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13743{
13744 struct alc_spec *spec = codec->spec;
13745 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13746 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13747 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13748 unsigned int dac_vol1, dac_vol2;
13749
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013750 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013751 snd_hda_codec_write(codec, speaker_nid, 0,
13752 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013753 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013754 snd_hda_codec_write(codec, 0x0f, 0,
13755 AC_VERB_SET_AMP_GAIN_MUTE,
13756 AMP_IN_UNMUTE(1));
13757 snd_hda_codec_write(codec, 0x10, 0,
13758 AC_VERB_SET_AMP_GAIN_MUTE,
13759 AMP_IN_UNMUTE(1));
13760 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013761 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013762 snd_hda_codec_write(codec, 0x0f, 0,
13763 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13764 snd_hda_codec_write(codec, 0x10, 0,
13765 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13766 }
13767
13768 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013769 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013770 dac_vol2 = AMP_OUT_ZERO;
13771 else if (line_nid == 0x15)
13772 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013773 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013774 dac_vol2 = AMP_OUT_ZERO;
13775 else if (hp_nid == 0x15)
13776 dac_vol1 = AMP_OUT_ZERO;
13777 if (line_nid != 0x16 || hp_nid != 0x16 ||
13778 spec->autocfg.line_out_pins[1] != 0x16 ||
13779 spec->autocfg.line_out_pins[2] != 0x16)
13780 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13781
13782 snd_hda_codec_write(codec, 0x02, 0,
13783 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13784 snd_hda_codec_write(codec, 0x03, 0,
13785 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13786}
13787
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013788/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013789#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13790#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013791#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013792#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13793
13794/*
13795 * BIOS auto configuration
13796 */
13797static int alc268_parse_auto_config(struct hda_codec *codec)
13798{
13799 struct alc_spec *spec = codec->spec;
13800 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013801 static const hda_nid_t alc268_ignore[] = { 0 };
Kailang Yanga361d842007-06-05 12:30:55 +020013802
13803 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13804 alc268_ignore);
13805 if (err < 0)
13806 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013807 if (!spec->autocfg.line_outs) {
13808 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13809 spec->multiout.max_channels = 2;
13810 spec->no_analog = 1;
13811 goto dig_only;
13812 }
Kailang Yanga361d842007-06-05 12:30:55 +020013813 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013814 }
Kailang Yanga361d842007-06-05 12:30:55 +020013815 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13816 if (err < 0)
13817 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013818 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013819 if (err < 0)
13820 return err;
13821
13822 spec->multiout.max_channels = 2;
13823
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013824 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013825 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013826 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013827 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013828 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013829
Takashi Iwai892981f2009-03-02 08:04:35 +010013830 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013831 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013832
Takashi Iwaid88897e2008-10-31 15:01:37 +010013833 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013834 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013835 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013836
Takashi Iwai776e1842007-08-29 15:07:11 +020013837 err = alc_auto_add_mic_boost(codec);
13838 if (err < 0)
13839 return err;
13840
Kailang Yang6227cdc2010-02-25 08:36:52 +010013841 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013842
Kailang Yanga361d842007-06-05 12:30:55 +020013843 return 1;
13844}
13845
Kailang Yanga361d842007-06-05 12:30:55 +020013846#define alc268_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010013847#define alc268_auto_init_input_src alc882_auto_init_input_src
Kailang Yanga361d842007-06-05 12:30:55 +020013848
13849/* init callback for auto-configuration model -- overriding the default init */
13850static void alc268_auto_init(struct hda_codec *codec)
13851{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013852 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013853 alc268_auto_init_multi_out(codec);
13854 alc268_auto_init_hp_out(codec);
13855 alc268_auto_init_mono_speaker_out(codec);
13856 alc268_auto_init_analog_input(codec);
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010013857 alc268_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013858 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013859 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013860 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013861}
13862
13863/*
13864 * configuration and preset
13865 */
Takashi Iwaiea734962011-01-17 11:29:34 +010013866static const char * const alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013867 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013868 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013869 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013870 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013871 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013872 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013873 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013874 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013875#ifdef CONFIG_SND_DEBUG
13876 [ALC268_TEST] = "test",
13877#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013878 [ALC268_AUTO] = "auto",
13879};
13880
Takashi Iwaia9111322011-05-02 11:30:18 +020013881static const struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013882 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013883 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013884 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013885 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013886 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013887 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13888 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013889 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chen0a1896b2011-06-06 18:55:34 -040013890 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013891 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13892 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013893 /* almost compatible with toshiba but with optional digital outs;
13894 * auto-probing seems working fine
13895 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013896 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013897 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013898 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013899 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013900 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013901 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013902 {}
13903};
13904
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013905/* Toshiba laptops have no unique PCI SSID but only codec SSID */
Takashi Iwaia9111322011-05-02 11:30:18 +020013906static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013907 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13908 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13909 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13910 ALC268_TOSHIBA),
13911 {}
13912};
13913
Takashi Iwaia9111322011-05-02 11:30:18 +020013914static const struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013915 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013916 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13917 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013918 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13919 alc267_quanta_il1_verbs },
13920 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13921 .dac_nids = alc268_dac_nids,
13922 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13923 .adc_nids = alc268_adc_nids_alt,
13924 .hp_nid = 0x03,
13925 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13926 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013927 .unsol_event = alc_sku_unsol_event,
13928 .setup = alc267_quanta_il1_setup,
13929 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013930 },
Kailang Yanga361d842007-06-05 12:30:55 +020013931 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013932 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13933 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013934 .init_verbs = { alc268_base_init_verbs },
13935 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13936 .dac_nids = alc268_dac_nids,
13937 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13938 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013939 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013940 .hp_nid = 0x03,
13941 .dig_out_nid = ALC268_DIGOUT_NID,
13942 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13943 .channel_mode = alc268_modes,
13944 .input_mux = &alc268_capture_source,
13945 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013946 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013947 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013948 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013949 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13950 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013951 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13952 .dac_nids = alc268_dac_nids,
13953 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13954 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013955 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013956 .hp_nid = 0x03,
13957 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13958 .channel_mode = alc268_modes,
13959 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013960 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013961 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013962 .init_hook = alc_inithook,
Takashi Iwaid2738092007-08-16 14:59:45 +020013963 },
13964 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013965 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013966 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013967 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13968 alc268_acer_verbs },
13969 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13970 .dac_nids = alc268_dac_nids,
13971 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13972 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013973 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013974 .hp_nid = 0x02,
13975 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13976 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013977 .input_mux = &alc268_acer_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013978 .unsol_event = alc_sku_unsol_event,
13979 .setup = alc268_acer_setup,
13980 .init_hook = alc_inithook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013981 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013982 [ALC268_ACER_DMIC] = {
13983 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13984 alc268_beep_mixer },
13985 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13986 alc268_acer_verbs },
13987 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13988 .dac_nids = alc268_dac_nids,
13989 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13990 .adc_nids = alc268_adc_nids_alt,
13991 .capsrc_nids = alc268_capsrc_nids,
13992 .hp_nid = 0x02,
13993 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13994 .channel_mode = alc268_modes,
13995 .input_mux = &alc268_acer_dmic_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013996 .unsol_event = alc_sku_unsol_event,
13997 .setup = alc268_acer_setup,
13998 .init_hook = alc_inithook,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013999 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020014000 [ALC268_ACER_ASPIRE_ONE] = {
14001 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010014002 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014003 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020014004 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14005 alc268_acer_aspire_one_verbs },
14006 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14007 .dac_nids = alc268_dac_nids,
14008 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14009 .adc_nids = alc268_adc_nids_alt,
14010 .capsrc_nids = alc268_capsrc_nids,
14011 .hp_nid = 0x03,
14012 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14013 .channel_mode = alc268_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014014 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014015 .setup = alc268_acer_lc_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014016 .init_hook = alc_inithook,
Kailang Yang8ef355d2008-08-26 13:10:22 +020014017 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014018 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014019 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
14020 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014021 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14022 alc268_dell_verbs },
14023 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14024 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014025 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14026 .adc_nids = alc268_adc_nids_alt,
14027 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014028 .hp_nid = 0x02,
14029 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14030 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020014031 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014032 .setup = alc268_dell_setup,
14033 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014034 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014035 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014036 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
14037 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014038 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14039 alc268_toshiba_verbs },
14040 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14041 .dac_nids = alc268_dac_nids,
14042 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14043 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010014044 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014045 .hp_nid = 0x03,
14046 .dig_out_nid = ALC268_DIGOUT_NID,
14047 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14048 .channel_mode = alc268_modes,
14049 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020014050 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014051 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020014052 .init_hook = alc_inithook,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010014053 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010014054#ifdef CONFIG_SND_DEBUG
14055 [ALC268_TEST] = {
14056 .mixers = { alc268_test_mixer, alc268_capture_mixer },
14057 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
14058 alc268_volume_init_verbs },
14059 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
14060 .dac_nids = alc268_dac_nids,
14061 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
14062 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010014063 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010014064 .hp_nid = 0x03,
14065 .dig_out_nid = ALC268_DIGOUT_NID,
14066 .num_channel_mode = ARRAY_SIZE(alc268_modes),
14067 .channel_mode = alc268_modes,
14068 .input_mux = &alc268_capture_source,
14069 },
14070#endif
Kailang Yanga361d842007-06-05 12:30:55 +020014071};
14072
14073static int patch_alc268(struct hda_codec *codec)
14074{
14075 struct alc_spec *spec;
14076 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010014077 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020014078
Julia Lawallef86f582009-12-19 08:18:03 +010014079 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020014080 if (spec == NULL)
14081 return -ENOMEM;
14082
14083 codec->spec = spec;
14084
14085 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
14086 alc268_models,
14087 alc268_cfg_tbl);
14088
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014089 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
14090 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010014091 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020014092
Kailang Yanga361d842007-06-05 12:30:55 +020014093 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014094 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14095 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020014096 board_config = ALC268_AUTO;
14097 }
14098
14099 if (board_config == ALC268_AUTO) {
14100 /* automatic parse from the BIOS config */
14101 err = alc268_parse_auto_config(codec);
14102 if (err < 0) {
14103 alc_free(codec);
14104 return err;
14105 } else if (!err) {
14106 printk(KERN_INFO
14107 "hda_codec: Cannot set up configuration "
14108 "from BIOS. Using base mode...\n");
14109 board_config = ALC268_3ST;
14110 }
14111 }
14112
14113 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014114 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020014115
Kailang Yanga361d842007-06-05 12:30:55 +020014116 spec->stream_analog_playback = &alc268_pcm_analog_playback;
14117 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010014118 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020014119
Kailang Yanga361d842007-06-05 12:30:55 +020014120 spec->stream_digital_playback = &alc268_pcm_digital_playback;
14121
Takashi Iwai22971e32009-02-10 11:56:44 +010014122 has_beep = 0;
14123 for (i = 0; i < spec->num_mixers; i++) {
14124 if (spec->mixers[i] == alc268_beep_mixer) {
14125 has_beep = 1;
14126 break;
14127 }
14128 }
14129
14130 if (has_beep) {
14131 err = snd_hda_attach_beep_device(codec, 0x1);
14132 if (err < 0) {
14133 alc_free(codec);
14134 return err;
14135 }
14136 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
14137 /* override the amp caps for beep generator */
14138 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014139 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
14140 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
14141 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
14142 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010014143 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010014144
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014145 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014146 /* check whether NID 0x07 is valid */
14147 unsigned int wcap = get_wcaps(codec, 0x07);
Kailang Yanga361d842007-06-05 12:30:55 +020014148
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014149 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014150 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020014151 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014152 if (spec->auto_mic ||
14153 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014154 spec->adc_nids = alc268_adc_nids_alt;
14155 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014156 if (spec->auto_mic)
14157 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014158 if (spec->auto_mic || spec->input_mux->num_items == 1)
14159 add_mixer(spec, alc268_capture_nosrc_mixer);
14160 else
14161 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014162 } else {
14163 spec->adc_nids = alc268_adc_nids;
14164 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010014165 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020014166 }
14167 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010014168
14169 spec->vmaster_nid = 0x02;
14170
Kailang Yanga361d842007-06-05 12:30:55 +020014171 codec->patch_ops = alc_patch_ops;
14172 if (board_config == ALC268_AUTO)
14173 spec->init_hook = alc268_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020014174 spec->shutup = alc_eapd_shutup;
Kailang Yangea1fb292008-08-26 12:58:38 +020014175
Kailang Yangbf1b0222010-10-21 08:49:56 +020014176 alc_init_jacks(codec);
14177
Kailang Yanga361d842007-06-05 12:30:55 +020014178 return 0;
14179}
14180
14181/*
Kailang Yangf6a92242007-12-13 16:52:54 +010014182 * ALC269 channel source setting (2 channel)
14183 */
14184#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
14185
14186#define alc269_dac_nids alc260_dac_nids
14187
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014188static const hda_nid_t alc269_adc_nids[1] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014189 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020014190 0x08,
14191};
14192
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014193static const hda_nid_t alc269_capsrc_nids[1] = {
Takashi Iwaie01bf502008-08-21 16:25:07 +020014194 0x23,
14195};
14196
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014197static const hda_nid_t alc269vb_adc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014198 /* ADC1 */
14199 0x09,
14200};
14201
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014202static const hda_nid_t alc269vb_capsrc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014203 0x22,
14204};
14205
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014206static const hda_nid_t alc269_adc_candidates[] = {
David Henningsson262ac222011-04-07 11:43:00 +020014207 0x08, 0x09, 0x07, 0x11,
Takashi Iwai66946352010-03-29 17:21:45 +020014208};
Takashi Iwaie01bf502008-08-21 16:25:07 +020014209
Kailang Yangf6a92242007-12-13 16:52:54 +010014210#define alc269_modes alc260_modes
14211#define alc269_capture_source alc880_lg_lw_capture_source
14212
Takashi Iwaia9111322011-05-02 11:30:18 +020014213static const struct snd_kcontrol_new alc269_base_mixer[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014214 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14215 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14216 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14217 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14218 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14219 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014220 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014221 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14222 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014223 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014224 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14225 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
14226 { } /* end */
14227};
14228
Takashi Iwaia9111322011-05-02 11:30:18 +020014229static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014230 /* output mixer control */
14231 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14232 {
14233 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14234 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014235 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020014236 .info = snd_hda_mixer_amp_switch_info,
14237 .get = snd_hda_mixer_amp_switch_get,
14238 .put = alc268_acer_master_sw_put,
14239 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14240 },
14241 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14242 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014243 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014244 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14245 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014246 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014247 { }
14248};
14249
Takashi Iwaia9111322011-05-02 11:30:18 +020014250static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
Tony Vroon64154832008-11-06 15:08:49 +000014251 /* output mixer control */
14252 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14253 {
14254 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14255 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014256 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000014257 .info = snd_hda_mixer_amp_switch_info,
14258 .get = snd_hda_mixer_amp_switch_get,
14259 .put = alc268_acer_master_sw_put,
14260 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14261 },
14262 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14263 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014264 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014265 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14266 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014267 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014268 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
14269 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014270 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014271 { }
14272};
14273
Takashi Iwaia9111322011-05-02 11:30:18 +020014274static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020014275 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014276 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020014277 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014278 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020014279 { } /* end */
14280};
14281
Takashi Iwaia9111322011-05-02 11:30:18 +020014282static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014283 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14284 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14285 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14286 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14287 { } /* end */
14288};
14289
Takashi Iwaia9111322011-05-02 11:30:18 +020014290static const struct snd_kcontrol_new alc269_asus_mixer[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014291 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14292 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
14293 { } /* end */
14294};
14295
Kailang Yangf6a92242007-12-13 16:52:54 +010014296/* capture mixer elements */
Takashi Iwaia9111322011-05-02 11:30:18 +020014297static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014298 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14299 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014300 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14301 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014302 { } /* end */
14303};
14304
Takashi Iwaia9111322011-05-02 11:30:18 +020014305static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020014306 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14307 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014308 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010014309 { } /* end */
14310};
14311
Takashi Iwaia9111322011-05-02 11:30:18 +020014312static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014313 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14314 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014315 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14316 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014317 { } /* end */
14318};
14319
Takashi Iwaia9111322011-05-02 11:30:18 +020014320static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014321 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14322 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014323 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014324 { } /* end */
14325};
14326
Takashi Iwai26f5df22008-11-03 17:39:46 +010014327/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010014328#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020014329
Takashi Iwaia9111322011-05-02 11:30:18 +020014330static const struct hda_verb alc269_quanta_fl1_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014331 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14332 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14333 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14334 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14335 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14336 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14337 { }
14338};
14339
Takashi Iwaia9111322011-05-02 11:30:18 +020014340static const struct hda_verb alc269_lifebook_verbs[] = {
Tony Vroon64154832008-11-06 15:08:49 +000014341 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14342 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
14343 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14344 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14345 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14346 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14347 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14348 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14349 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14350 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14351 { }
14352};
14353
Kailang Yang60db6b52008-08-26 13:13:00 +020014354/* toggle speaker-output according to the hp-jack state */
14355static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
14356{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014357 alc_hp_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014358
14359 snd_hda_codec_write(codec, 0x20, 0,
14360 AC_VERB_SET_COEF_INDEX, 0x0c);
14361 snd_hda_codec_write(codec, 0x20, 0,
14362 AC_VERB_SET_PROC_COEF, 0x680);
14363
14364 snd_hda_codec_write(codec, 0x20, 0,
14365 AC_VERB_SET_COEF_INDEX, 0x0c);
14366 snd_hda_codec_write(codec, 0x20, 0,
14367 AC_VERB_SET_PROC_COEF, 0x480);
14368}
14369
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014370#define alc269_lifebook_speaker_automute \
14371 alc269_quanta_fl1_speaker_automute
Tony Vroon64154832008-11-06 15:08:49 +000014372
Tony Vroon64154832008-11-06 15:08:49 +000014373static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
14374{
14375 unsigned int present_laptop;
14376 unsigned int present_dock;
14377
Wu Fengguang864f92b2009-11-18 12:38:02 +080014378 present_laptop = snd_hda_jack_detect(codec, 0x18);
14379 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000014380
14381 /* Laptop mic port overrides dock mic port, design decision */
14382 if (present_dock)
14383 snd_hda_codec_write(codec, 0x23, 0,
14384 AC_VERB_SET_CONNECT_SEL, 0x3);
14385 if (present_laptop)
14386 snd_hda_codec_write(codec, 0x23, 0,
14387 AC_VERB_SET_CONNECT_SEL, 0x0);
14388 if (!present_dock && !present_laptop)
14389 snd_hda_codec_write(codec, 0x23, 0,
14390 AC_VERB_SET_CONNECT_SEL, 0x1);
14391}
14392
Kailang Yang60db6b52008-08-26 13:13:00 +020014393static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14394 unsigned int res)
14395{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014396 switch (res >> 26) {
14397 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014398 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014399 break;
14400 case ALC880_MIC_EVENT:
14401 alc_mic_automute(codec);
14402 break;
14403 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014404}
14405
Tony Vroon64154832008-11-06 15:08:49 +000014406static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14407 unsigned int res)
14408{
14409 if ((res >> 26) == ALC880_HP_EVENT)
14410 alc269_lifebook_speaker_automute(codec);
14411 if ((res >> 26) == ALC880_MIC_EVENT)
14412 alc269_lifebook_mic_autoswitch(codec);
14413}
14414
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014415static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14416{
14417 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014418 spec->autocfg.hp_pins[0] = 0x15;
14419 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014420 spec->automute_mixer_nid[0] = 0x0c;
14421 spec->automute = 1;
14422 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014423 spec->ext_mic.pin = 0x18;
14424 spec->ext_mic.mux_idx = 0;
14425 spec->int_mic.pin = 0x19;
14426 spec->int_mic.mux_idx = 1;
14427 spec->auto_mic = 1;
14428}
14429
Kailang Yang60db6b52008-08-26 13:13:00 +020014430static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14431{
14432 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014433 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014434}
14435
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014436static void alc269_lifebook_setup(struct hda_codec *codec)
14437{
14438 struct alc_spec *spec = codec->spec;
14439 spec->autocfg.hp_pins[0] = 0x15;
14440 spec->autocfg.hp_pins[1] = 0x1a;
14441 spec->autocfg.speaker_pins[0] = 0x14;
14442 spec->automute_mixer_nid[0] = 0x0c;
14443 spec->automute = 1;
14444 spec->automute_mode = ALC_AUTOMUTE_MIXER;
14445}
14446
Tony Vroon64154832008-11-06 15:08:49 +000014447static void alc269_lifebook_init_hook(struct hda_codec *codec)
14448{
14449 alc269_lifebook_speaker_automute(codec);
14450 alc269_lifebook_mic_autoswitch(codec);
14451}
14452
Takashi Iwaia9111322011-05-02 11:30:18 +020014453static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014454 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14455 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14456 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14457 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14458 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14459 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14460 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14461 {}
14462};
14463
Takashi Iwaia9111322011-05-02 11:30:18 +020014464static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014465 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14466 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14467 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14468 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14469 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14470 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14471 {}
14472};
14473
Takashi Iwaia9111322011-05-02 11:30:18 +020014474static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014475 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14476 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14477 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14478 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14479 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14480 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14481 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14482 {}
14483};
14484
Takashi Iwaia9111322011-05-02 11:30:18 +020014485static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014486 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14487 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14488 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14489 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14490 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14491 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14492 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14493 {}
14494};
14495
Takashi Iwaia9111322011-05-02 11:30:18 +020014496static const struct hda_verb alc271_acer_dmic_verbs[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014497 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14498 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14499 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14500 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14501 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14502 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14503 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14504 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14505 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14506 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14507 { }
14508};
14509
Kailang Yang226b1ec2010-04-09 11:01:20 +020014510static void alc269_laptop_amic_setup(struct hda_codec *codec)
14511{
14512 struct alc_spec *spec = codec->spec;
14513 spec->autocfg.hp_pins[0] = 0x15;
14514 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014515 spec->automute_mixer_nid[0] = 0x0c;
14516 spec->automute = 1;
14517 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014518 spec->ext_mic.pin = 0x18;
14519 spec->ext_mic.mux_idx = 0;
14520 spec->int_mic.pin = 0x19;
14521 spec->int_mic.mux_idx = 1;
14522 spec->auto_mic = 1;
14523}
14524
Kailang Yang84898e82010-02-04 14:16:14 +010014525static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014526{
14527 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014528 spec->autocfg.hp_pins[0] = 0x15;
14529 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014530 spec->automute_mixer_nid[0] = 0x0c;
14531 spec->automute = 1;
14532 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014533 spec->ext_mic.pin = 0x18;
14534 spec->ext_mic.mux_idx = 0;
14535 spec->int_mic.pin = 0x12;
14536 spec->int_mic.mux_idx = 5;
14537 spec->auto_mic = 1;
14538}
14539
Kailang Yang226b1ec2010-04-09 11:01:20 +020014540static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014541{
14542 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014543 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014544 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014545 spec->automute_mixer_nid[0] = 0x0c;
14546 spec->automute = 1;
14547 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014548 spec->ext_mic.pin = 0x18;
14549 spec->ext_mic.mux_idx = 0;
14550 spec->int_mic.pin = 0x19;
14551 spec->int_mic.mux_idx = 1;
14552 spec->auto_mic = 1;
14553}
14554
Kailang Yang226b1ec2010-04-09 11:01:20 +020014555static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14556{
14557 struct alc_spec *spec = codec->spec;
14558 spec->autocfg.hp_pins[0] = 0x21;
14559 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014560 spec->automute_mixer_nid[0] = 0x0c;
14561 spec->automute = 1;
14562 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014563 spec->ext_mic.pin = 0x18;
14564 spec->ext_mic.mux_idx = 0;
14565 spec->int_mic.pin = 0x12;
14566 spec->int_mic.mux_idx = 6;
14567 spec->auto_mic = 1;
14568}
14569
Kailang Yangf6a92242007-12-13 16:52:54 +010014570/*
14571 * generic initialization of ADC, input mixers and output mixers
14572 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014573static const struct hda_verb alc269_init_verbs[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014574 /*
14575 * Unmute ADC0 and set the default input to mic-in
14576 */
Kailang Yang84898e82010-02-04 14:16:14 +010014577 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014578
14579 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014580 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014581 */
14582 /* set vol=0 to output mixers */
14583 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14584 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14585
14586 /* set up input amps for analog loopback */
14587 /* Amp Indices: DAC = 0, mixer = 1 */
14588 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14589 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14590 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14591 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14592 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14593 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14594
14595 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14596 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14597 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14598 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14599 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14600 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14601 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14602
14603 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14604 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014605
Kailang Yang84898e82010-02-04 14:16:14 +010014606 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014607 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14608 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014609 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014610
14611 /* set EAPD */
14612 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014613 { }
14614};
14615
Takashi Iwaia9111322011-05-02 11:30:18 +020014616static const struct hda_verb alc269vb_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014617 /*
14618 * Unmute ADC0 and set the default input to mic-in
14619 */
14620 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14621
14622 /*
14623 * Set up output mixers (0x02 - 0x03)
14624 */
14625 /* set vol=0 to output mixers */
14626 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14627 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14628
14629 /* set up input amps for analog loopback */
14630 /* Amp Indices: DAC = 0, mixer = 1 */
14631 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14632 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14633 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14634 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14635 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14636 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14637
14638 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14639 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14640 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14641 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14642 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14643 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14644 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14645
14646 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14647 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14648
14649 /* FIXME: use Mux-type input source selection */
14650 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14651 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14652 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14653
14654 /* set EAPD */
14655 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014656 { }
14657};
14658
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014659#define alc269_auto_create_multi_out_ctls \
14660 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014661#define alc269_auto_create_input_ctls \
14662 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014663
14664#ifdef CONFIG_SND_HDA_POWER_SAVE
14665#define alc269_loopbacks alc880_loopbacks
14666#endif
14667
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014668/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014669#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14670#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14671#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14672#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14673
Takashi Iwaia9111322011-05-02 11:30:18 +020014674static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014675 .substreams = 1,
14676 .channels_min = 2,
14677 .channels_max = 8,
14678 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14679 /* NID is set in alc_build_pcms */
14680 .ops = {
14681 .open = alc880_playback_pcm_open,
14682 .prepare = alc880_playback_pcm_prepare,
14683 .cleanup = alc880_playback_pcm_cleanup
14684 },
14685};
14686
Takashi Iwaia9111322011-05-02 11:30:18 +020014687static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014688 .substreams = 1,
14689 .channels_min = 2,
14690 .channels_max = 2,
14691 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14692 /* NID is set in alc_build_pcms */
14693};
14694
Takashi Iwaiad358792010-03-30 18:00:59 +020014695#ifdef CONFIG_SND_HDA_POWER_SAVE
14696static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14697{
14698 switch (codec->subsystem_id) {
14699 case 0x103c1586:
14700 return 1;
14701 }
14702 return 0;
14703}
14704
14705static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14706{
14707 /* update mute-LED according to the speaker mute state */
14708 if (nid == 0x01 || nid == 0x14) {
14709 int pinval;
14710 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14711 HDA_AMP_MUTE)
14712 pinval = 0x24;
14713 else
14714 pinval = 0x20;
14715 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014716 snd_hda_codec_update_cache(codec, 0x19, 0,
14717 AC_VERB_SET_PIN_WIDGET_CONTROL,
14718 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014719 }
14720 return alc_check_power_status(codec, nid);
14721}
14722#endif /* CONFIG_SND_HDA_POWER_SAVE */
14723
Takashi Iwai840b64c2010-07-13 22:49:01 +020014724static int alc275_setup_dual_adc(struct hda_codec *codec)
14725{
14726 struct alc_spec *spec = codec->spec;
14727
14728 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14729 return 0;
14730 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14731 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14732 if (spec->ext_mic.pin <= 0x12) {
14733 spec->private_adc_nids[0] = 0x08;
14734 spec->private_adc_nids[1] = 0x11;
14735 spec->private_capsrc_nids[0] = 0x23;
14736 spec->private_capsrc_nids[1] = 0x22;
14737 } else {
14738 spec->private_adc_nids[0] = 0x11;
14739 spec->private_adc_nids[1] = 0x08;
14740 spec->private_capsrc_nids[0] = 0x22;
14741 spec->private_capsrc_nids[1] = 0x23;
14742 }
14743 spec->adc_nids = spec->private_adc_nids;
14744 spec->capsrc_nids = spec->private_capsrc_nids;
14745 spec->num_adc_nids = 2;
14746 spec->dual_adc_switch = 1;
14747 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14748 spec->adc_nids[0], spec->adc_nids[1]);
14749 return 1;
14750 }
14751 return 0;
14752}
14753
Takashi Iwaid433a672010-09-20 15:11:54 +020014754/* different alc269-variants */
14755enum {
14756 ALC269_TYPE_NORMAL,
Kailang Yang48c88e82010-11-23 08:56:16 +010014757 ALC269_TYPE_ALC258,
Takashi Iwaid433a672010-09-20 15:11:54 +020014758 ALC269_TYPE_ALC259,
Kailang Yang48c88e82010-11-23 08:56:16 +010014759 ALC269_TYPE_ALC269VB,
14760 ALC269_TYPE_ALC270,
Takashi Iwaid433a672010-09-20 15:11:54 +020014761 ALC269_TYPE_ALC271X,
14762};
14763
Kailang Yangf6a92242007-12-13 16:52:54 +010014764/*
14765 * BIOS auto configuration
14766 */
14767static int alc269_parse_auto_config(struct hda_codec *codec)
14768{
14769 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014770 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014771 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Kailang Yangf6a92242007-12-13 16:52:54 +010014772
14773 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14774 alc269_ignore);
14775 if (err < 0)
14776 return err;
14777
14778 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14779 if (err < 0)
14780 return err;
Takashi Iwaif3550d12010-09-20 15:09:03 +020014781 if (spec->codec_variant == ALC269_TYPE_NORMAL)
14782 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14783 else
14784 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14785 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014786 if (err < 0)
14787 return err;
14788
14789 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14790
Takashi Iwai757899a2010-07-30 10:48:14 +020014791 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014792
Takashi Iwai603c4012008-07-30 15:01:44 +020014793 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014794 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014795
Takashi Iwaid433a672010-09-20 15:11:54 +020014796 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Kailang Yang84898e82010-02-04 14:16:14 +010014797 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014798 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014799 } else {
14800 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014801 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014802 }
14803
Kailang Yangf6a92242007-12-13 16:52:54 +010014804 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014805 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014806
14807 if (!alc275_setup_dual_adc(codec))
14808 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14809 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014810
Kailang Yangf6a92242007-12-13 16:52:54 +010014811 err = alc_auto_add_mic_boost(codec);
14812 if (err < 0)
14813 return err;
14814
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014815 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014816 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014817
Kailang Yangf6a92242007-12-13 16:52:54 +010014818 return 1;
14819}
14820
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014821#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14822#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014823#define alc269_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010014824#define alc269_auto_init_input_src alc882_auto_init_input_src
Kailang Yangf6a92242007-12-13 16:52:54 +010014825
14826
14827/* init callback for auto-configuration model -- overriding the default init */
14828static void alc269_auto_init(struct hda_codec *codec)
14829{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014830 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014831 alc269_auto_init_multi_out(codec);
14832 alc269_auto_init_hp_out(codec);
14833 alc269_auto_init_analog_input(codec);
Takashi Iwaiae0ebbf2011-03-10 14:11:59 +010014834 if (!spec->dual_adc_switch)
14835 alc269_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014836 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014837 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014838 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014839}
14840
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014841static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14842{
14843 int val = alc_read_coef_idx(codec, 0x04);
14844 if (power_up)
14845 val |= 1 << 11;
14846 else
14847 val &= ~(1 << 11);
14848 alc_write_coef_idx(codec, 0x04, val);
14849}
14850
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014851static void alc269_shutup(struct hda_codec *codec)
Kailang Yang977ddd62010-09-15 10:02:29 +020014852{
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014853 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14854 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014855 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014856 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014857 msleep(150);
14858 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014859}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014860
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014861#ifdef SND_HDA_NEEDS_RESUME
Kailang Yang977ddd62010-09-15 10:02:29 +020014862static int alc269_resume(struct hda_codec *codec)
14863{
Kailang Yang977ddd62010-09-15 10:02:29 +020014864 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014865 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014866 msleep(150);
14867 }
14868
14869 codec->patch_ops.init(codec);
14870
14871 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014872 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014873 msleep(200);
14874 }
14875
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014876 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14877 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014878
14879 snd_hda_codec_resume_amp(codec);
14880 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014881 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014882 return 0;
14883}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014884#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014885
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014886static void alc269_fixup_hweq(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014887 const struct alc_fixup *fix, int action)
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014888{
14889 int coef;
14890
Takashi Iwai58701122011-01-13 15:41:45 +010014891 if (action != ALC_FIXUP_ACT_INIT)
Takashi Iwai9fb1ef252011-01-13 14:40:43 +010014892 return;
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014893 coef = alc_read_coef_idx(codec, 0x1e);
14894 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
14895}
14896
Takashi Iwai6981d182011-04-15 10:11:12 +020014897static void alc271_fixup_dmic(struct hda_codec *codec,
14898 const struct alc_fixup *fix, int action)
14899{
Takashi Iwaia9111322011-05-02 11:30:18 +020014900 static const struct hda_verb verbs[] = {
Takashi Iwai6981d182011-04-15 10:11:12 +020014901 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14902 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14903 {}
14904 };
14905 unsigned int cfg;
14906
14907 if (strcmp(codec->chip_name, "ALC271X"))
14908 return;
14909 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
14910 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
14911 snd_hda_sequence_write(codec, verbs);
14912}
14913
Takashi Iwaiff818c22010-04-12 08:59:25 +020014914enum {
14915 ALC269_FIXUP_SONY_VAIO,
Takashi Iwai74dc8902011-01-13 14:14:41 +010014916 ALC275_FIXUP_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014917 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014918 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014919 ALC269_FIXUP_ASUS_G73JW,
Kailang Yang357f9152011-01-12 08:12:52 +010014920 ALC269_FIXUP_LENOVO_EAPD,
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014921 ALC275_FIXUP_SONY_HWEQ,
Takashi Iwai6981d182011-04-15 10:11:12 +020014922 ALC271_FIXUP_DMIC,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014923};
14924
Takashi Iwaiff818c22010-04-12 08:59:25 +020014925static const struct alc_fixup alc269_fixups[] = {
14926 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014927 .type = ALC_FIXUP_VERBS,
14928 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020014929 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14930 {}
14931 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014932 },
Takashi Iwai74dc8902011-01-13 14:14:41 +010014933 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014934 .type = ALC_FIXUP_VERBS,
14935 .v.verbs = (const struct hda_verb[]) {
Kailang Yang27855912010-12-21 09:09:53 +010014936 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14937 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14938 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14939 { }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014940 },
14941 .chained = true,
14942 .chain_id = ALC269_FIXUP_SONY_VAIO
Kailang Yang27855912010-12-21 09:09:53 +010014943 },
David Henningsson145a9022010-09-16 10:07:53 +020014944 [ALC269_FIXUP_DELL_M101Z] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014945 .type = ALC_FIXUP_VERBS,
14946 .v.verbs = (const struct hda_verb[]) {
David Henningsson145a9022010-09-16 10:07:53 +020014947 /* Enables internal speaker */
14948 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14949 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14950 {}
14951 }
14952 },
David Henningsson022c92b2010-12-17 20:43:04 +010014953 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014954 .type = ALC_FIXUP_SKU,
14955 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonfe67b242010-12-15 08:01:46 +010014956 },
David Henningssonac612402010-12-15 09:18:18 +010014957 [ALC269_FIXUP_ASUS_G73JW] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014958 .type = ALC_FIXUP_PINS,
14959 .v.pins = (const struct alc_pincfg[]) {
David Henningssonac612402010-12-15 09:18:18 +010014960 { 0x17, 0x99130111 }, /* subwoofer */
14961 { }
14962 }
14963 },
Kailang Yang357f9152011-01-12 08:12:52 +010014964 [ALC269_FIXUP_LENOVO_EAPD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014965 .type = ALC_FIXUP_VERBS,
14966 .v.verbs = (const struct hda_verb[]) {
Kailang Yang357f9152011-01-12 08:12:52 +010014967 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
14968 {}
14969 }
14970 },
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014971 [ALC275_FIXUP_SONY_HWEQ] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014972 .type = ALC_FIXUP_FUNC,
14973 .v.func = alc269_fixup_hweq,
14974 .chained = true,
14975 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
Takashi Iwai6981d182011-04-15 10:11:12 +020014976 },
14977 [ALC271_FIXUP_DMIC] = {
14978 .type = ALC_FIXUP_FUNC,
14979 .v.func = alc271_fixup_dmic,
14980 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014981};
14982
Takashi Iwaia9111322011-05-02 11:30:18 +020014983static const struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai74dc8902011-01-13 14:14:41 +010014984 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014985 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
14986 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
Takashi Iwai7039c742010-12-23 16:35:34 +010014987 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014988 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Takashi Iwai6981d182011-04-15 10:11:12 +020014989 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
David Henningsson022c92b2010-12-17 20:43:04 +010014990 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonded9f522011-01-26 11:46:12 +010014991 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
14992 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
14993 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
14994 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014995 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Kailang Yang357f9152011-01-12 08:12:52 +010014996 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014997 {}
14998};
14999
15000
Kailang Yangf6a92242007-12-13 16:52:54 +010015001/*
15002 * configuration and preset
15003 */
Takashi Iwaiea734962011-01-17 11:29:34 +010015004static const char * const alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020015005 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020015006 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010015007 [ALC269_AMIC] = "laptop-amic",
15008 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000015009 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020015010 [ALC269_LIFEBOOK] = "lifebook",
15011 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010015012};
15013
Takashi Iwaia9111322011-05-02 11:30:18 +020015014static const struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020015015 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015016 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020015017 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010015018 ALC269_AMIC),
15019 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
15020 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
15021 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
15022 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
15023 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
15024 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
15025 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
15026 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
15027 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
Chih-Wei Huangc790ad32011-02-25 11:14:31 +080015028 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
Kailang Yang84898e82010-02-04 14:16:14 +010015029 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
15030 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
15031 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
15032 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
15033 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
15034 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
15035 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
15036 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
15037 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
15038 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
15039 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
15040 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
15041 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
15042 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
15043 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
15044 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
15045 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
15046 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
15047 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
15048 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
15049 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
15050 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
15051 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
15052 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
15053 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
15054 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020015055 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010015056 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020015057 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010015058 ALC269_DMIC),
15059 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
15060 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020015061 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000015062 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010015063 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
15064 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
15065 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
15066 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
15067 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
15068 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010015069 {}
15070};
15071
Takashi Iwaia9111322011-05-02 11:30:18 +020015072static const struct alc_config_preset alc269_presets[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010015073 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015074 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010015075 .init_verbs = { alc269_init_verbs },
15076 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15077 .dac_nids = alc269_dac_nids,
15078 .hp_nid = 0x03,
15079 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15080 .channel_mode = alc269_modes,
15081 .input_mux = &alc269_capture_source,
15082 },
Kailang Yang60db6b52008-08-26 13:13:00 +020015083 [ALC269_QUANTA_FL1] = {
15084 .mixers = { alc269_quanta_fl1_mixer },
15085 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
15086 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15087 .dac_nids = alc269_dac_nids,
15088 .hp_nid = 0x03,
15089 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15090 .channel_mode = alc269_modes,
15091 .input_mux = &alc269_capture_source,
15092 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020015093 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020015094 .init_hook = alc269_quanta_fl1_init_hook,
15095 },
Kailang Yang84898e82010-02-04 14:16:14 +010015096 [ALC269_AMIC] = {
15097 .mixers = { alc269_laptop_mixer },
15098 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015099 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015100 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015101 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15102 .dac_nids = alc269_dac_nids,
15103 .hp_nid = 0x03,
15104 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15105 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015106 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015107 .setup = alc269_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015108 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015109 },
Kailang Yang84898e82010-02-04 14:16:14 +010015110 [ALC269_DMIC] = {
15111 .mixers = { alc269_laptop_mixer },
15112 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020015113 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015114 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020015115 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15116 .dac_nids = alc269_dac_nids,
15117 .hp_nid = 0x03,
15118 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15119 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015120 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015121 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015122 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010015123 },
15124 [ALC269VB_AMIC] = {
15125 .mixers = { alc269vb_laptop_mixer },
15126 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
15127 .init_verbs = { alc269vb_init_verbs,
15128 alc269vb_laptop_amic_init_verbs },
15129 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15130 .dac_nids = alc269_dac_nids,
15131 .hp_nid = 0x03,
15132 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15133 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015134 .unsol_event = alc_sku_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020015135 .setup = alc269vb_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015136 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010015137 },
15138 [ALC269VB_DMIC] = {
15139 .mixers = { alc269vb_laptop_mixer },
15140 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15141 .init_verbs = { alc269vb_init_verbs,
15142 alc269vb_laptop_dmic_init_verbs },
15143 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15144 .dac_nids = alc269_dac_nids,
15145 .hp_nid = 0x03,
15146 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15147 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015148 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015149 .setup = alc269vb_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015150 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015151 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015152 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015153 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010015154 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015155 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015156 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015157 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15158 .dac_nids = alc269_dac_nids,
15159 .hp_nid = 0x03,
15160 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15161 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015162 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010015163 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015164 .init_hook = alc_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015165 },
Tony Vroon64154832008-11-06 15:08:49 +000015166 [ALC269_LIFEBOOK] = {
15167 .mixers = { alc269_lifebook_mixer },
15168 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
15169 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15170 .dac_nids = alc269_dac_nids,
15171 .hp_nid = 0x03,
15172 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15173 .channel_mode = alc269_modes,
15174 .input_mux = &alc269_capture_source,
15175 .unsol_event = alc269_lifebook_unsol_event,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020015176 .setup = alc269_lifebook_setup,
Tony Vroon64154832008-11-06 15:08:49 +000015177 .init_hook = alc269_lifebook_init_hook,
15178 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015179 [ALC271_ACER] = {
15180 .mixers = { alc269_asus_mixer },
15181 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15182 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
15183 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15184 .dac_nids = alc269_dac_nids,
15185 .adc_nids = alc262_dmic_adc_nids,
15186 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
15187 .capsrc_nids = alc262_dmic_capsrc_nids,
15188 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15189 .channel_mode = alc269_modes,
15190 .input_mux = &alc269_capture_source,
15191 .dig_out_nid = ALC880_DIGOUT_NID,
15192 .unsol_event = alc_sku_unsol_event,
15193 .setup = alc269vb_laptop_dmic_setup,
15194 .init_hook = alc_inithook,
15195 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015196};
15197
Kailang Yang977ddd62010-09-15 10:02:29 +020015198static int alc269_fill_coef(struct hda_codec *codec)
15199{
15200 int val;
15201
15202 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
15203 alc_write_coef_idx(codec, 0xf, 0x960b);
15204 alc_write_coef_idx(codec, 0xe, 0x8817);
15205 }
15206
15207 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
15208 alc_write_coef_idx(codec, 0xf, 0x960b);
15209 alc_write_coef_idx(codec, 0xe, 0x8814);
15210 }
15211
15212 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
15213 val = alc_read_coef_idx(codec, 0x04);
15214 /* Power up output pin */
15215 alc_write_coef_idx(codec, 0x04, val | (1<<11));
15216 }
15217
15218 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
15219 val = alc_read_coef_idx(codec, 0xd);
15220 if ((val & 0x0c00) >> 10 != 0x1) {
15221 /* Capless ramp up clock control */
Kailang Yangb896b4e2011-05-18 11:53:16 +020015222 alc_write_coef_idx(codec, 0xd, val | (1<<10));
Kailang Yang977ddd62010-09-15 10:02:29 +020015223 }
15224 val = alc_read_coef_idx(codec, 0x17);
15225 if ((val & 0x01c0) >> 6 != 0x4) {
15226 /* Class D power on reset */
Kailang Yangb896b4e2011-05-18 11:53:16 +020015227 alc_write_coef_idx(codec, 0x17, val | (1<<7));
Kailang Yang977ddd62010-09-15 10:02:29 +020015228 }
15229 }
Kailang Yangb896b4e2011-05-18 11:53:16 +020015230
15231 val = alc_read_coef_idx(codec, 0xd); /* Class D */
15232 alc_write_coef_idx(codec, 0xd, val | (1<<14));
15233
15234 val = alc_read_coef_idx(codec, 0x4); /* HP */
15235 alc_write_coef_idx(codec, 0x4, val | (1<<11));
15236
Kailang Yang977ddd62010-09-15 10:02:29 +020015237 return 0;
15238}
15239
Kailang Yangf6a92242007-12-13 16:52:54 +010015240static int patch_alc269(struct hda_codec *codec)
15241{
15242 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010015243 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010015244 int err;
15245
15246 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15247 if (spec == NULL)
15248 return -ENOMEM;
15249
15250 codec->spec = spec;
15251
Kailang Yangda00c242010-03-19 11:23:45 +010015252 alc_auto_parse_customize_define(codec);
15253
Kailang Yangc793bec2010-12-21 09:14:13 +010015254 if (codec->vendor_id == 0x10ec0269) {
15255 coef = alc_read_coef_idx(codec, 0);
15256 if ((coef & 0x00f0) == 0x0010) {
15257 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
15258 spec->cdefine.platform_type == 1) {
15259 alc_codec_rename(codec, "ALC271X");
15260 spec->codec_variant = ALC269_TYPE_ALC271X;
15261 } else if ((coef & 0xf000) == 0x1000) {
15262 spec->codec_variant = ALC269_TYPE_ALC270;
15263 } else if ((coef & 0xf000) == 0x2000) {
15264 alc_codec_rename(codec, "ALC259");
15265 spec->codec_variant = ALC269_TYPE_ALC259;
15266 } else if ((coef & 0xf000) == 0x3000) {
15267 alc_codec_rename(codec, "ALC258");
15268 spec->codec_variant = ALC269_TYPE_ALC258;
15269 } else {
15270 alc_codec_rename(codec, "ALC269VB");
15271 spec->codec_variant = ALC269_TYPE_ALC269VB;
15272 }
15273 } else
15274 alc_fix_pll_init(codec, 0x20, 0x04, 15);
15275 alc269_fill_coef(codec);
15276 }
Kailang Yang977ddd62010-09-15 10:02:29 +020015277
Kailang Yangf6a92242007-12-13 16:52:54 +010015278 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
15279 alc269_models,
15280 alc269_cfg_tbl);
15281
15282 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015283 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15284 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010015285 board_config = ALC269_AUTO;
15286 }
15287
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015288 if (board_config == ALC269_AUTO) {
15289 alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
15290 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
15291 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020015292
Kailang Yangf6a92242007-12-13 16:52:54 +010015293 if (board_config == ALC269_AUTO) {
15294 /* automatic parse from the BIOS config */
15295 err = alc269_parse_auto_config(codec);
15296 if (err < 0) {
15297 alc_free(codec);
15298 return err;
15299 } else if (!err) {
15300 printk(KERN_INFO
15301 "hda_codec: Cannot set up configuration "
15302 "from BIOS. Using base mode...\n");
15303 board_config = ALC269_BASIC;
15304 }
15305 }
15306
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015307 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020015308 err = snd_hda_attach_beep_device(codec, 0x1);
15309 if (err < 0) {
15310 alc_free(codec);
15311 return err;
15312 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015313 }
15314
Kailang Yangf6a92242007-12-13 16:52:54 +010015315 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015316 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010015317
Kailang Yang84898e82010-02-04 14:16:14 +010015318 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010015319 /* Due to a hardware problem on Lenovo Ideadpad, we need to
15320 * fix the sample rate of analog I/O to 44.1kHz
15321 */
15322 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
15323 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020015324 } else if (spec->dual_adc_switch) {
15325 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15326 /* switch ADC dynamically */
15327 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010015328 } else {
15329 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15330 spec->stream_analog_capture = &alc269_pcm_analog_capture;
15331 }
Kailang Yangf6a92242007-12-13 16:52:54 +010015332 spec->stream_digital_playback = &alc269_pcm_digital_playback;
15333 spec->stream_digital_capture = &alc269_pcm_digital_capture;
15334
Takashi Iwai66946352010-03-29 17:21:45 +020015335 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Kailang Yang1657cbd2010-11-23 08:53:32 +010015336 if (spec->codec_variant == ALC269_TYPE_NORMAL) {
Takashi Iwai66946352010-03-29 17:21:45 +020015337 spec->adc_nids = alc269_adc_nids;
15338 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
15339 spec->capsrc_nids = alc269_capsrc_nids;
15340 } else {
15341 spec->adc_nids = alc269vb_adc_nids;
15342 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
15343 spec->capsrc_nids = alc269vb_capsrc_nids;
15344 }
Kailang Yang84898e82010-02-04 14:16:14 +010015345 }
15346
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015347 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015348 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015349 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010015350 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010015351
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015352 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaiff818c22010-04-12 08:59:25 +020015353
Takashi Iwai100d5eb2009-08-10 11:55:51 +020015354 spec->vmaster_nid = 0x02;
15355
Kailang Yangf6a92242007-12-13 16:52:54 +010015356 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020015357#ifdef SND_HDA_NEEDS_RESUME
15358 codec->patch_ops.resume = alc269_resume;
15359#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010015360 if (board_config == ALC269_AUTO)
15361 spec->init_hook = alc269_auto_init;
Takashi Iwai5402e4c2011-04-07 10:39:25 +020015362 spec->shutup = alc269_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020015363
15364 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010015365#ifdef CONFIG_SND_HDA_POWER_SAVE
15366 if (!spec->loopback.amplist)
15367 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020015368 if (alc269_mic2_for_mute_led(codec))
15369 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010015370#endif
15371
15372 return 0;
15373}
15374
15375/*
Kailang Yangdf694da2005-12-05 19:42:22 +010015376 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15377 */
15378
15379/*
15380 * set the path ways for 2 channel output
15381 * need to set the codec line out and mic 1 pin widgets to inputs
15382 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015383static const struct hda_verb alc861_threestack_ch2_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015384 /* set pin widget 1Ah (line in) for input */
15385 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015386 /* set pin widget 18h (mic1/2) for input, for mic also enable
15387 * the vref
15388 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015389 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15390
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015391 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15392#if 0
15393 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15394 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15395#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015396 { } /* end */
15397};
15398/*
15399 * 6ch mode
15400 * need to set the codec line out and mic 1 pin widgets to outputs
15401 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015402static const struct hda_verb alc861_threestack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015403 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15404 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15405 /* set pin widget 18h (mic1) for output (CLFE)*/
15406 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15407
15408 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015409 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015410
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015411 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15412#if 0
15413 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15414 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15415#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015416 { } /* end */
15417};
15418
Takashi Iwaia9111322011-05-02 11:30:18 +020015419static const struct hda_channel_mode alc861_threestack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015420 { 2, alc861_threestack_ch2_init },
15421 { 6, alc861_threestack_ch6_init },
15422};
Takashi Iwai22309c32006-08-09 16:57:28 +020015423/* Set mic1 as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015424static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015425 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15426 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15427 { } /* end */
15428};
15429/* Set mic1 as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015430static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015431 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15432 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15433 { } /* end */
15434};
15435
Takashi Iwaia9111322011-05-02 11:30:18 +020015436static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015437 { 2, alc861_uniwill_m31_ch2_init },
15438 { 4, alc861_uniwill_m31_ch4_init },
15439};
Kailang Yangdf694da2005-12-05 19:42:22 +010015440
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015441/* Set mic1 and line-in as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015442static const struct hda_verb alc861_asus_ch2_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015443 /* set pin widget 1Ah (line in) for input */
15444 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015445 /* set pin widget 18h (mic1/2) for input, for mic also enable
15446 * the vref
15447 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015448 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15449
15450 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15451#if 0
15452 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15453 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15454#endif
15455 { } /* end */
15456};
15457/* Set mic1 nad line-in as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015458static const struct hda_verb alc861_asus_ch6_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015459 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15460 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15461 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15462 /* set pin widget 18h (mic1) for output (CLFE)*/
15463 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15464 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15465 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15466 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15467
15468 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15469#if 0
15470 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15471 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15472#endif
15473 { } /* end */
15474};
15475
Takashi Iwaia9111322011-05-02 11:30:18 +020015476static const struct hda_channel_mode alc861_asus_modes[2] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015477 { 2, alc861_asus_ch2_init },
15478 { 6, alc861_asus_ch6_init },
15479};
15480
Kailang Yangdf694da2005-12-05 19:42:22 +010015481/* patch-ALC861 */
15482
Takashi Iwaia9111322011-05-02 11:30:18 +020015483static const struct snd_kcontrol_new alc861_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015484 /* output mixer control */
15485 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15486 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15487 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15488 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15489 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15490
15491 /*Input mixer control */
15492 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15493 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15494 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15495 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15496 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15497 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15498 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15499 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15500 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15501 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015502
Kailang Yangdf694da2005-12-05 19:42:22 +010015503 { } /* end */
15504};
15505
Takashi Iwaia9111322011-05-02 11:30:18 +020015506static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015507 /* output mixer control */
15508 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15509 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15510 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15511 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15512 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15513
15514 /* Input mixer control */
15515 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15516 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15517 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15518 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15519 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15520 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15521 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15522 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15523 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15524 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015525
Kailang Yangdf694da2005-12-05 19:42:22 +010015526 {
15527 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15528 .name = "Channel Mode",
15529 .info = alc_ch_mode_info,
15530 .get = alc_ch_mode_get,
15531 .put = alc_ch_mode_put,
15532 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15533 },
15534 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015535};
15536
Takashi Iwaia9111322011-05-02 11:30:18 +020015537static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015538 /* output mixer control */
15539 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15540 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15541 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015542
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015543 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015544};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015545
Takashi Iwaia9111322011-05-02 11:30:18 +020015546static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015547 /* output mixer control */
15548 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15549 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15550 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15551 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15552 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15553
15554 /* Input mixer control */
15555 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15556 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15557 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15558 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15559 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15560 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15561 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15562 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15563 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15564 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015565
Takashi Iwai22309c32006-08-09 16:57:28 +020015566 {
15567 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15568 .name = "Channel Mode",
15569 .info = alc_ch_mode_info,
15570 .get = alc_ch_mode_get,
15571 .put = alc_ch_mode_put,
15572 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15573 },
15574 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015575};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015576
Takashi Iwaia9111322011-05-02 11:30:18 +020015577static const struct snd_kcontrol_new alc861_asus_mixer[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015578 /* output mixer control */
15579 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15580 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15581 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15582 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15583 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15584
15585 /* Input mixer control */
15586 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15587 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15588 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15589 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15590 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15591 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15592 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15593 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15594 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015595 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15596
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015597 {
15598 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15599 .name = "Channel Mode",
15600 .info = alc_ch_mode_info,
15601 .get = alc_ch_mode_get,
15602 .put = alc_ch_mode_put,
15603 .private_value = ARRAY_SIZE(alc861_asus_modes),
15604 },
15605 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015606};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015607
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015608/* additional mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015609static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015610 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15611 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015612 { }
15613};
15614
Kailang Yangdf694da2005-12-05 19:42:22 +010015615/*
15616 * generic initialization of ADC, input mixers and output mixers
15617 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015618static const struct hda_verb alc861_base_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015619 /*
15620 * Unmute ADC0 and set the default input to mic-in
15621 */
15622 /* port-A for surround (rear panel) */
15623 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15624 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15625 /* port-B for mic-in (rear panel) with vref */
15626 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15627 /* port-C for line-in (rear panel) */
15628 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15629 /* port-D for Front */
15630 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15631 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15632 /* port-E for HP out (front panel) */
15633 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15634 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015635 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015636 /* port-F for mic-in (front panel) with vref */
15637 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15638 /* port-G for CLFE (rear panel) */
15639 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15640 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15641 /* port-H for side (rear panel) */
15642 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15643 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15644 /* CD-in */
15645 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15646 /* route front mic to ADC1*/
15647 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15648 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015649
Kailang Yangdf694da2005-12-05 19:42:22 +010015650 /* Unmute DAC0~3 & spdif out*/
15651 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15652 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15653 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15654 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15655 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015656
Kailang Yangdf694da2005-12-05 19:42:22 +010015657 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15658 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15659 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15660 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15661 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015662
Kailang Yangdf694da2005-12-05 19:42:22 +010015663 /* Unmute Stereo Mixer 15 */
15664 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15665 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15666 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015667 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015668
15669 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15670 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15671 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15672 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15673 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15674 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15675 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15676 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015677 /* hp used DAC 3 (Front) */
15678 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015679 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15680
15681 { }
15682};
15683
Takashi Iwaia9111322011-05-02 11:30:18 +020015684static const struct hda_verb alc861_threestack_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015685 /*
15686 * Unmute ADC0 and set the default input to mic-in
15687 */
15688 /* port-A for surround (rear panel) */
15689 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15690 /* port-B for mic-in (rear panel) with vref */
15691 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15692 /* port-C for line-in (rear panel) */
15693 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15694 /* port-D for Front */
15695 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15696 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15697 /* port-E for HP out (front panel) */
15698 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15699 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015700 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015701 /* port-F for mic-in (front panel) with vref */
15702 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15703 /* port-G for CLFE (rear panel) */
15704 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15705 /* port-H for side (rear panel) */
15706 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15707 /* CD-in */
15708 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15709 /* route front mic to ADC1*/
15710 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15711 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15712 /* Unmute DAC0~3 & spdif out*/
15713 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15714 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15715 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15716 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15717 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015718
Kailang Yangdf694da2005-12-05 19:42:22 +010015719 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15720 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15721 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15722 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15723 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015724
Kailang Yangdf694da2005-12-05 19:42:22 +010015725 /* Unmute Stereo Mixer 15 */
15726 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15727 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15728 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015729 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015730
15731 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15732 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15733 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15734 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15735 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15736 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15737 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15738 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015739 /* hp used DAC 3 (Front) */
15740 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015741 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15742 { }
15743};
Takashi Iwai22309c32006-08-09 16:57:28 +020015744
Takashi Iwaia9111322011-05-02 11:30:18 +020015745static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015746 /*
15747 * Unmute ADC0 and set the default input to mic-in
15748 */
15749 /* port-A for surround (rear panel) */
15750 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15751 /* port-B for mic-in (rear panel) with vref */
15752 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15753 /* port-C for line-in (rear panel) */
15754 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15755 /* port-D for Front */
15756 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15757 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15758 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015759 /* this has to be set to VREF80 */
15760 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015761 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015762 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015763 /* port-F for mic-in (front panel) with vref */
15764 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15765 /* port-G for CLFE (rear panel) */
15766 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15767 /* port-H for side (rear panel) */
15768 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15769 /* CD-in */
15770 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15771 /* route front mic to ADC1*/
15772 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15773 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15774 /* Unmute DAC0~3 & spdif out*/
15775 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15776 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15777 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15778 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15779 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015780
Takashi Iwai22309c32006-08-09 16:57:28 +020015781 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15782 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15783 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15784 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15785 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015786
Takashi Iwai22309c32006-08-09 16:57:28 +020015787 /* Unmute Stereo Mixer 15 */
15788 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15789 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15790 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015791 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015792
15793 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15794 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15795 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15796 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15797 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15798 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15799 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15800 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015801 /* hp used DAC 3 (Front) */
15802 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015803 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15804 { }
15805};
15806
Takashi Iwaia9111322011-05-02 11:30:18 +020015807static const struct hda_verb alc861_asus_init_verbs[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015808 /*
15809 * Unmute ADC0 and set the default input to mic-in
15810 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015811 /* port-A for surround (rear panel)
15812 * according to codec#0 this is the HP jack
15813 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015814 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15815 /* route front PCM to HP */
15816 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15817 /* port-B for mic-in (rear panel) with vref */
15818 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15819 /* port-C for line-in (rear panel) */
15820 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15821 /* port-D for Front */
15822 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15823 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15824 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015825 /* this has to be set to VREF80 */
15826 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015827 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015828 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015829 /* port-F for mic-in (front panel) with vref */
15830 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15831 /* port-G for CLFE (rear panel) */
15832 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15833 /* port-H for side (rear panel) */
15834 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15835 /* CD-in */
15836 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15837 /* route front mic to ADC1*/
15838 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15839 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15840 /* Unmute DAC0~3 & spdif out*/
15841 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15842 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15843 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15844 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15845 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15846 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15847 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15848 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15849 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15850 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015851
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015852 /* Unmute Stereo Mixer 15 */
15853 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15854 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15855 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015856 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015857
15858 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15859 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15860 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15861 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15862 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15863 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15864 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15865 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015866 /* hp used DAC 3 (Front) */
15867 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015868 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15869 { }
15870};
15871
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015872/* additional init verbs for ASUS laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020015873static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015874 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15875 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15876 { }
15877};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015878
Kailang Yangdf694da2005-12-05 19:42:22 +010015879/*
15880 * generic initialization of ADC, input mixers and output mixers
15881 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015882static const struct hda_verb alc861_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015883 /*
15884 * Unmute ADC0 and set the default input to mic-in
15885 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015886 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015887 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015888
Kailang Yangdf694da2005-12-05 19:42:22 +010015889 /* Unmute DAC0~3 & spdif out*/
15890 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15891 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15892 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15893 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15894 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015895
Kailang Yangdf694da2005-12-05 19:42:22 +010015896 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15897 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15898 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15899 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15900 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015901
Kailang Yangdf694da2005-12-05 19:42:22 +010015902 /* Unmute Stereo Mixer 15 */
15903 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15904 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15905 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15906 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15907
Takashi Iwai1c209302009-07-22 15:17:45 +020015908 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15909 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15910 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15911 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15912 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15913 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15914 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15915 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015916
15917 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15918 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015919 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15920 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015921 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15922 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015923 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15924 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015925
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015926 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015927
15928 { }
15929};
15930
Takashi Iwaia9111322011-05-02 11:30:18 +020015931static const struct hda_verb alc861_toshiba_init_verbs[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015932 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015933
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015934 { }
15935};
15936
15937/* toggle speaker-output according to the hp-jack state */
15938static void alc861_toshiba_automute(struct hda_codec *codec)
15939{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015940 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015941
Takashi Iwai47fd8302007-08-10 17:11:07 +020015942 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15943 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15944 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15945 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015946}
15947
15948static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15949 unsigned int res)
15950{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015951 if ((res >> 26) == ALC880_HP_EVENT)
15952 alc861_toshiba_automute(codec);
15953}
15954
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015955/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015956#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15957#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15958#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15959#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15960
15961
15962#define ALC861_DIGOUT_NID 0x07
15963
Takashi Iwaia9111322011-05-02 11:30:18 +020015964static const struct hda_channel_mode alc861_8ch_modes[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015965 { 8, NULL }
15966};
15967
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015968static const hda_nid_t alc861_dac_nids[4] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015969 /* front, surround, clfe, side */
15970 0x03, 0x06, 0x05, 0x04
15971};
15972
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015973static const hda_nid_t alc660_dac_nids[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015974 /* front, clfe, surround */
15975 0x03, 0x05, 0x06
15976};
15977
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015978static const hda_nid_t alc861_adc_nids[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015979 /* ADC0-2 */
15980 0x08,
15981};
15982
Takashi Iwaia9111322011-05-02 11:30:18 +020015983static const struct hda_input_mux alc861_capture_source = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015984 .num_items = 5,
15985 .items = {
15986 { "Mic", 0x0 },
15987 { "Front Mic", 0x3 },
15988 { "Line", 0x1 },
15989 { "CD", 0x4 },
15990 { "Mixer", 0x5 },
15991 },
15992};
15993
Takashi Iwai1c209302009-07-22 15:17:45 +020015994static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15995{
15996 struct alc_spec *spec = codec->spec;
15997 hda_nid_t mix, srcs[5];
15998 int i, j, num;
15999
16000 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
16001 return 0;
16002 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
16003 if (num < 0)
16004 return 0;
16005 for (i = 0; i < num; i++) {
16006 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020016007 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020016008 if (type != AC_WID_AUD_OUT)
16009 continue;
16010 for (j = 0; j < spec->multiout.num_dacs; j++)
16011 if (spec->multiout.dac_nids[j] == srcs[i])
16012 break;
16013 if (j >= spec->multiout.num_dacs)
16014 return srcs[i];
16015 }
16016 return 0;
16017}
16018
Kailang Yangdf694da2005-12-05 19:42:22 +010016019/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020016020static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016021 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010016022{
Takashi Iwai1c209302009-07-22 15:17:45 +020016023 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016024 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020016025 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010016026
16027 spec->multiout.dac_nids = spec->private_dac_nids;
16028 for (i = 0; i < cfg->line_outs; i++) {
16029 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020016030 dac = alc861_look_for_dac(codec, nid);
16031 if (!dac)
16032 continue;
Takashi Iwaidda14412011-05-02 11:29:30 +020016033 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010016034 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016035 return 0;
16036}
16037
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016038static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
16039 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016040{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016041 return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai1c209302009-07-22 15:17:45 +020016042 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
16043}
16044
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016045#define alc861_create_out_sw(codec, pfx, nid, chs) \
16046 __alc861_create_out_sw(codec, pfx, nid, 0, chs)
16047
Takashi Iwai1c209302009-07-22 15:17:45 +020016048/* add playback controls from the parsed DAC table */
16049static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
16050 const struct auto_pin_cfg *cfg)
16051{
16052 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010016053 static const char * const chname[4] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016054 "Front", "Surround", NULL /*CLFE*/, "Side"
16055 };
Takashi Iwaice764ab2011-04-27 16:35:23 +020016056 const char *pfx = alc_get_line_out_pfx(spec, true);
Kailang Yangdf694da2005-12-05 19:42:22 +010016057 hda_nid_t nid;
Takashi Iwaice764ab2011-04-27 16:35:23 +020016058 int i, err, noutputs;
Takashi Iwai1c209302009-07-22 15:17:45 +020016059
Takashi Iwaice764ab2011-04-27 16:35:23 +020016060 noutputs = cfg->line_outs;
16061 if (spec->multi_ios > 0)
16062 noutputs += spec->multi_ios;
16063
16064 for (i = 0; i < noutputs; i++) {
Kailang Yangdf694da2005-12-05 19:42:22 +010016065 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016066 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010016067 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016068 if (!pfx && i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010016069 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020016070 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016071 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016072 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016073 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016074 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016075 return err;
16076 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016077 const char *name = pfx;
David Henningsson5a882642011-03-23 08:35:07 +010016078 int index = i;
16079 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016080 name = chname[i];
David Henningsson5a882642011-03-23 08:35:07 +010016081 index = 0;
16082 }
16083 err = __alc861_create_out_sw(codec, name, nid, index, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016084 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016085 return err;
16086 }
16087 }
16088 return 0;
16089}
16090
Takashi Iwai1c209302009-07-22 15:17:45 +020016091static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016092{
Takashi Iwai1c209302009-07-22 15:17:45 +020016093 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016094 int err;
16095 hda_nid_t nid;
16096
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016097 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010016098 return 0;
16099
16100 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020016101 nid = alc861_look_for_dac(codec, pin);
16102 if (nid) {
16103 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
16104 if (err < 0)
16105 return err;
16106 spec->multiout.hp_nid = nid;
16107 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016108 }
16109 return 0;
16110}
16111
16112/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016113static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016114 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010016115{
Takashi Iwai05f5f472009-08-25 13:10:18 +020016116 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010016117}
16118
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016119static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
16120 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020016121 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010016122{
Takashi Iwai1c209302009-07-22 15:17:45 +020016123 hda_nid_t mix, srcs[5];
16124 int i, num;
16125
Jacek Luczak564c5be2008-05-03 18:41:23 +020016126 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
16127 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020016128 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020016129 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020016130 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
16131 return;
16132 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
16133 if (num < 0)
16134 return;
16135 for (i = 0; i < num; i++) {
16136 unsigned int mute;
16137 if (srcs[i] == dac || srcs[i] == 0x15)
16138 mute = AMP_IN_UNMUTE(i);
16139 else
16140 mute = AMP_IN_MUTE(i);
16141 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
16142 mute);
16143 }
Kailang Yangdf694da2005-12-05 19:42:22 +010016144}
16145
16146static void alc861_auto_init_multi_out(struct hda_codec *codec)
16147{
16148 struct alc_spec *spec = codec->spec;
16149 int i;
16150
16151 for (i = 0; i < spec->autocfg.line_outs; i++) {
16152 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016153 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016154 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016155 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016156 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016157 }
16158}
16159
16160static void alc861_auto_init_hp_out(struct hda_codec *codec)
16161{
16162 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016163
Takashi Iwai15870f02009-10-05 08:25:13 +020016164 if (spec->autocfg.hp_outs)
16165 alc861_auto_set_output_and_unmute(codec,
16166 spec->autocfg.hp_pins[0],
16167 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020016168 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020016169 if (spec->autocfg.speaker_outs)
16170 alc861_auto_set_output_and_unmute(codec,
16171 spec->autocfg.speaker_pins[0],
16172 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020016173 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016174}
16175
16176static void alc861_auto_init_analog_input(struct hda_codec *codec)
16177{
16178 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016179 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010016180 int i;
16181
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016182 for (i = 0; i < cfg->num_inputs; i++) {
16183 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai23f0c042009-02-26 13:03:58 +010016184 if (nid >= 0x0c && nid <= 0x11)
Takashi Iwai30ea0982010-09-16 18:47:56 +020016185 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016186 }
16187}
16188
16189/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016190/* return 1 if successful, 0 if the proper config is not found,
16191 * or a negative error code
16192 */
Kailang Yangdf694da2005-12-05 19:42:22 +010016193static int alc861_parse_auto_config(struct hda_codec *codec)
16194{
16195 struct alc_spec *spec = codec->spec;
16196 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016197 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010016198
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016199 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16200 alc861_ignore);
16201 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016202 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016203 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016204 return 0; /* can't find valid BIOS pin config */
16205
Takashi Iwai1c209302009-07-22 15:17:45 +020016206 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016207 if (err < 0)
16208 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020016209 err = alc_auto_add_multi_channel_mode(codec);
16210 if (err < 0)
16211 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016212 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016213 if (err < 0)
16214 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016215 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016216 if (err < 0)
16217 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016218 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016219 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016220 return err;
16221
16222 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16223
Takashi Iwai757899a2010-07-30 10:48:14 +020016224 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016225
Takashi Iwai603c4012008-07-30 15:01:44 +020016226 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016227 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010016228
Takashi Iwaid88897e2008-10-31 15:01:37 +010016229 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010016230
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020016231 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016232 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010016233
16234 spec->adc_nids = alc861_adc_nids;
16235 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016236 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016237
Kailang Yang6227cdc2010-02-25 08:36:52 +010016238 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016239
Kailang Yangdf694da2005-12-05 19:42:22 +010016240 return 1;
16241}
16242
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016243/* additional initialization for auto-configuration model */
16244static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010016245{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016246 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016247 alc861_auto_init_multi_out(codec);
16248 alc861_auto_init_hp_out(codec);
16249 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016250 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016251 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016252 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016253}
16254
Takashi Iwaicb53c622007-08-10 17:21:45 +020016255#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +020016256static const struct hda_amp_list alc861_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +020016257 { 0x15, HDA_INPUT, 0 },
16258 { 0x15, HDA_INPUT, 1 },
16259 { 0x15, HDA_INPUT, 2 },
16260 { 0x15, HDA_INPUT, 3 },
16261 { } /* end */
16262};
16263#endif
16264
Kailang Yangdf694da2005-12-05 19:42:22 +010016265
16266/*
16267 * configuration and preset
16268 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016269static const char * const alc861_models[ALC861_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016270 [ALC861_3ST] = "3stack",
16271 [ALC660_3ST] = "3stack-660",
16272 [ALC861_3ST_DIG] = "3stack-dig",
16273 [ALC861_6ST_DIG] = "6stack-dig",
16274 [ALC861_UNIWILL_M31] = "uniwill-m31",
16275 [ALC861_TOSHIBA] = "toshiba",
16276 [ALC861_ASUS] = "asus",
16277 [ALC861_ASUS_LAPTOP] = "asus-laptop",
16278 [ALC861_AUTO] = "auto",
16279};
16280
Takashi Iwaia9111322011-05-02 11:30:18 +020016281static const struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010016282 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016283 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16284 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16285 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016286 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020016287 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010016288 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020016289 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
16290 * Any other models that need this preset?
16291 */
16292 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020016293 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
16294 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016295 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
16296 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
16297 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
16298 /* FIXME: the below seems conflict */
16299 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
16300 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
16301 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010016302 {}
16303};
16304
Takashi Iwaia9111322011-05-02 11:30:18 +020016305static const struct alc_config_preset alc861_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010016306 [ALC861_3ST] = {
16307 .mixers = { alc861_3ST_mixer },
16308 .init_verbs = { alc861_threestack_init_verbs },
16309 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16310 .dac_nids = alc861_dac_nids,
16311 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16312 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016313 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016314 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16315 .adc_nids = alc861_adc_nids,
16316 .input_mux = &alc861_capture_source,
16317 },
16318 [ALC861_3ST_DIG] = {
16319 .mixers = { alc861_base_mixer },
16320 .init_verbs = { alc861_threestack_init_verbs },
16321 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16322 .dac_nids = alc861_dac_nids,
16323 .dig_out_nid = ALC861_DIGOUT_NID,
16324 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16325 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016326 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016327 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16328 .adc_nids = alc861_adc_nids,
16329 .input_mux = &alc861_capture_source,
16330 },
16331 [ALC861_6ST_DIG] = {
16332 .mixers = { alc861_base_mixer },
16333 .init_verbs = { alc861_base_init_verbs },
16334 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16335 .dac_nids = alc861_dac_nids,
16336 .dig_out_nid = ALC861_DIGOUT_NID,
16337 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
16338 .channel_mode = alc861_8ch_modes,
16339 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16340 .adc_nids = alc861_adc_nids,
16341 .input_mux = &alc861_capture_source,
16342 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016343 [ALC660_3ST] = {
16344 .mixers = { alc861_3ST_mixer },
16345 .init_verbs = { alc861_threestack_init_verbs },
16346 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
16347 .dac_nids = alc660_dac_nids,
16348 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16349 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016350 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016351 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16352 .adc_nids = alc861_adc_nids,
16353 .input_mux = &alc861_capture_source,
16354 },
Takashi Iwai22309c32006-08-09 16:57:28 +020016355 [ALC861_UNIWILL_M31] = {
16356 .mixers = { alc861_uniwill_m31_mixer },
16357 .init_verbs = { alc861_uniwill_m31_init_verbs },
16358 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16359 .dac_nids = alc861_dac_nids,
16360 .dig_out_nid = ALC861_DIGOUT_NID,
16361 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
16362 .channel_mode = alc861_uniwill_m31_modes,
16363 .need_dac_fix = 1,
16364 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16365 .adc_nids = alc861_adc_nids,
16366 .input_mux = &alc861_capture_source,
16367 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016368 [ALC861_TOSHIBA] = {
16369 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016370 .init_verbs = { alc861_base_init_verbs,
16371 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016372 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16373 .dac_nids = alc861_dac_nids,
16374 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16375 .channel_mode = alc883_3ST_2ch_modes,
16376 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16377 .adc_nids = alc861_adc_nids,
16378 .input_mux = &alc861_capture_source,
16379 .unsol_event = alc861_toshiba_unsol_event,
16380 .init_hook = alc861_toshiba_automute,
16381 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020016382 [ALC861_ASUS] = {
16383 .mixers = { alc861_asus_mixer },
16384 .init_verbs = { alc861_asus_init_verbs },
16385 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16386 .dac_nids = alc861_dac_nids,
16387 .dig_out_nid = ALC861_DIGOUT_NID,
16388 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
16389 .channel_mode = alc861_asus_modes,
16390 .need_dac_fix = 1,
16391 .hp_nid = 0x06,
16392 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16393 .adc_nids = alc861_adc_nids,
16394 .input_mux = &alc861_capture_source,
16395 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010016396 [ALC861_ASUS_LAPTOP] = {
16397 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
16398 .init_verbs = { alc861_asus_init_verbs,
16399 alc861_asus_laptop_init_verbs },
16400 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16401 .dac_nids = alc861_dac_nids,
16402 .dig_out_nid = ALC861_DIGOUT_NID,
16403 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16404 .channel_mode = alc883_3ST_2ch_modes,
16405 .need_dac_fix = 1,
16406 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16407 .adc_nids = alc861_adc_nids,
16408 .input_mux = &alc861_capture_source,
16409 },
16410};
Kailang Yangdf694da2005-12-05 19:42:22 +010016411
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016412/* Pin config fixes */
16413enum {
16414 PINFIX_FSC_AMILO_PI1505,
16415};
16416
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016417static const struct alc_fixup alc861_fixups[] = {
16418 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016419 .type = ALC_FIXUP_PINS,
16420 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020016421 { 0x0b, 0x0221101f }, /* HP */
16422 { 0x0f, 0x90170310 }, /* speaker */
16423 { }
16424 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016425 },
16426};
16427
Takashi Iwaia9111322011-05-02 11:30:18 +020016428static const struct snd_pci_quirk alc861_fixup_tbl[] = {
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016429 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
16430 {}
16431};
Kailang Yangdf694da2005-12-05 19:42:22 +010016432
16433static int patch_alc861(struct hda_codec *codec)
16434{
16435 struct alc_spec *spec;
16436 int board_config;
16437 int err;
16438
Robert P. J. Daydc041e02006-12-19 14:44:15 +010016439 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010016440 if (spec == NULL)
16441 return -ENOMEM;
16442
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016443 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016444
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016445 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
16446 alc861_models,
16447 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016448
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016449 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016450 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16451 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016452 board_config = ALC861_AUTO;
16453 }
16454
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016455 if (board_config == ALC861_AUTO) {
16456 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
16457 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16458 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016459
Kailang Yangdf694da2005-12-05 19:42:22 +010016460 if (board_config == ALC861_AUTO) {
16461 /* automatic parse from the BIOS config */
16462 err = alc861_parse_auto_config(codec);
16463 if (err < 0) {
16464 alc_free(codec);
16465 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016466 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016467 printk(KERN_INFO
16468 "hda_codec: Cannot set up configuration "
16469 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016470 board_config = ALC861_3ST_DIG;
16471 }
16472 }
16473
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016474 err = snd_hda_attach_beep_device(codec, 0x23);
16475 if (err < 0) {
16476 alc_free(codec);
16477 return err;
16478 }
16479
Kailang Yangdf694da2005-12-05 19:42:22 +010016480 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016481 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016482
Kailang Yangdf694da2005-12-05 19:42:22 +010016483 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16484 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16485
Kailang Yangdf694da2005-12-05 19:42:22 +010016486 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16487 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16488
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016489 if (!spec->cap_mixer)
16490 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016491 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16492
Takashi Iwai2134ea42008-01-10 16:53:55 +010016493 spec->vmaster_nid = 0x03;
16494
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016495 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016496
Kailang Yangdf694da2005-12-05 19:42:22 +010016497 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016498 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016499 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016500#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016501 spec->power_hook = alc_power_eapd;
16502#endif
16503 }
16504#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016505 if (!spec->loopback.amplist)
16506 spec->loopback.amplist = alc861_loopbacks;
16507#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016508
Kailang Yangdf694da2005-12-05 19:42:22 +010016509 return 0;
16510}
16511
16512/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016513 * ALC861-VD support
16514 *
16515 * Based on ALC882
16516 *
16517 * In addition, an independent DAC
16518 */
16519#define ALC861VD_DIGOUT_NID 0x06
16520
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016521static const hda_nid_t alc861vd_dac_nids[4] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016522 /* front, surr, clfe, side surr */
16523 0x02, 0x03, 0x04, 0x05
16524};
16525
16526/* dac_nids for ALC660vd are in a different order - according to
16527 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016528 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016529 * of ALC660vd codecs, but for now there is only 3stack mixer
16530 * - and it is the same as in 861vd.
16531 * adc_nids in ALC660vd are (is) the same as in 861vd
16532 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016533static const hda_nid_t alc660vd_dac_nids[3] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016534 /* front, rear, clfe, rear_surr */
16535 0x02, 0x04, 0x03
16536};
16537
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016538static const hda_nid_t alc861vd_adc_nids[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016539 /* ADC0 */
16540 0x09,
16541};
16542
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016543static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010016544
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016545/* input MUX */
16546/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020016547static const struct hda_input_mux alc861vd_capture_source = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016548 .num_items = 4,
16549 .items = {
16550 { "Mic", 0x0 },
16551 { "Front Mic", 0x1 },
16552 { "Line", 0x2 },
16553 { "CD", 0x4 },
16554 },
16555};
16556
Takashi Iwaia9111322011-05-02 11:30:18 +020016557static const struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016558 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016559 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010016560 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010016561 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016562 },
16563};
16564
Takashi Iwaia9111322011-05-02 11:30:18 +020016565static const struct hda_input_mux alc861vd_hp_capture_source = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016566 .num_items = 2,
16567 .items = {
16568 { "Front Mic", 0x0 },
16569 { "ATAPI Mic", 0x1 },
16570 },
16571};
16572
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016573/*
16574 * 2ch mode
16575 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016576static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016577 { 2, NULL }
16578};
16579
16580/*
16581 * 6ch mode
16582 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016583static const struct hda_verb alc861vd_6stack_ch6_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016584 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16585 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16586 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16587 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16588 { } /* end */
16589};
16590
16591/*
16592 * 8ch mode
16593 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016594static const struct hda_verb alc861vd_6stack_ch8_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016595 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16596 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16597 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16598 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16599 { } /* end */
16600};
16601
Takashi Iwaia9111322011-05-02 11:30:18 +020016602static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016603 { 6, alc861vd_6stack_ch6_init },
16604 { 8, alc861vd_6stack_ch8_init },
16605};
16606
Takashi Iwaia9111322011-05-02 11:30:18 +020016607static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016608 {
16609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16610 .name = "Channel Mode",
16611 .info = alc_ch_mode_info,
16612 .get = alc_ch_mode_get,
16613 .put = alc_ch_mode_put,
16614 },
16615 { } /* end */
16616};
16617
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016618/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16619 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16620 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016621static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016622 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16623 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16624
16625 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16626 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16627
16628 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16629 HDA_OUTPUT),
16630 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16631 HDA_OUTPUT),
16632 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16633 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16634
16635 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16636 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16637
16638 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16639
David Henningsson5f99f862011-01-04 15:24:24 +010016640 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016641 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16642 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16643
David Henningsson5f99f862011-01-04 15:24:24 +010016644 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016645 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16646 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16647
16648 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16649 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16650
16651 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16652 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16653
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016654 { } /* end */
16655};
16656
Takashi Iwaia9111322011-05-02 11:30:18 +020016657static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016658 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16659 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16660
16661 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16662
David Henningsson5f99f862011-01-04 15:24:24 +010016663 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016664 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16665 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16666
David Henningsson5f99f862011-01-04 15:24:24 +010016667 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016668 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16669 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16670
16671 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16672 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16673
16674 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16675 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16676
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016677 { } /* end */
16678};
16679
Takashi Iwaia9111322011-05-02 11:30:18 +020016680static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016681 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16682 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16683 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16684
16685 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16686
David Henningsson5f99f862011-01-04 15:24:24 +010016687 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016688 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16689 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16690
David Henningsson5f99f862011-01-04 15:24:24 +010016691 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016692 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16693 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16694
16695 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16696 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16697
16698 { } /* end */
16699};
16700
Tobin Davisb419f342008-03-07 11:57:51 +010016701/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016702 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016703 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016704static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016705 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16706 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016707 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16708 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016709 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016710 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16711 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016712 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016713 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16714 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016715 { } /* end */
16716};
16717
Kailang Yangd1a991a2007-08-15 16:21:59 +020016718/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16719 * Front Mic=0x18, ATAPI Mic = 0x19,
16720 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016721static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016722 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16723 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16724 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16725 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16726 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16727 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16728 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16729 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016730
Kailang Yangd1a991a2007-08-15 16:21:59 +020016731 { } /* end */
16732};
16733
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016734/*
16735 * generic initialization of ADC, input mixers and output mixers
16736 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016737static const struct hda_verb alc861vd_volume_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016738 /*
16739 * Unmute ADC0 and set the default input to mic-in
16740 */
16741 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16742 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16743
16744 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16745 * the analog-loopback mixer widget
16746 */
16747 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016748 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16749 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16750 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16751 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16752 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016753
16754 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016755 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16756 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16757 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016758 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016759
16760 /*
16761 * Set up output mixers (0x02 - 0x05)
16762 */
16763 /* set vol=0 to output mixers */
16764 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16765 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16766 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16767 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16768
16769 /* set up input amps for analog loopback */
16770 /* Amp Indices: DAC = 0, mixer = 1 */
16771 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16772 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16773 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16774 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16775 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16776 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16777 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16778 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16779
16780 { }
16781};
16782
16783/*
16784 * 3-stack pin configuration:
16785 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16786 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016787static const struct hda_verb alc861vd_3stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016788 /*
16789 * Set pin mode and muting
16790 */
16791 /* set front pin widgets 0x14 for output */
16792 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16793 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16794 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16795
16796 /* Mic (rear) pin: input vref at 80% */
16797 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16798 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16799 /* Front Mic pin: input vref at 80% */
16800 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16801 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16802 /* Line In pin: input */
16803 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16804 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16805 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16806 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16807 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16808 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16809 /* CD pin widget for input */
16810 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16811
16812 { }
16813};
16814
16815/*
16816 * 6-stack pin configuration:
16817 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016818static const struct hda_verb alc861vd_6stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016819 /*
16820 * Set pin mode and muting
16821 */
16822 /* set front pin widgets 0x14 for output */
16823 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16824 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16825 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16826
16827 /* Rear Pin: output 1 (0x0d) */
16828 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16829 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16830 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16831 /* CLFE Pin: output 2 (0x0e) */
16832 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16833 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16834 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16835 /* Side Pin: output 3 (0x0f) */
16836 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16837 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16838 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16839
16840 /* Mic (rear) pin: input vref at 80% */
16841 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16842 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16843 /* Front Mic pin: input vref at 80% */
16844 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16845 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16846 /* Line In pin: input */
16847 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16848 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16849 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16850 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16851 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16852 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16853 /* CD pin widget for input */
16854 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16855
16856 { }
16857};
16858
Takashi Iwaia9111322011-05-02 11:30:18 +020016859static const struct hda_verb alc861vd_eapd_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016860 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16861 { }
16862};
16863
Takashi Iwaia9111322011-05-02 11:30:18 +020016864static const struct hda_verb alc660vd_eapd_verbs[] = {
Kailang Yangf9423e72008-05-27 12:32:25 +020016865 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16866 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16867 { }
16868};
16869
Takashi Iwaia9111322011-05-02 11:30:18 +020016870static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016871 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16872 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16873 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16874 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016875 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016876 {}
16877};
16878
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016879static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016880{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016881 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016882 spec->autocfg.hp_pins[0] = 0x1b;
16883 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016884 spec->automute = 1;
16885 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016886}
16887
16888static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16889{
Takashi Iwaid922b512011-04-28 12:18:53 +020016890 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016891 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016892}
16893
16894static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16895 unsigned int res)
16896{
16897 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016898 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016899 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016900 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016901 default:
Takashi Iwaid922b512011-04-28 12:18:53 +020016902 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016903 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016904 }
16905}
16906
Takashi Iwaia9111322011-05-02 11:30:18 +020016907static const struct hda_verb alc861vd_dallas_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020016908 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16909 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16910 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16911 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16912
16913 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16914 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16915 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16916 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16917 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16918 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16919 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16920 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016921
Kailang Yang272a5272007-05-14 11:00:38 +020016922 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16923 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16924 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16925 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16926 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16927 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16928 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16929 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16930
16931 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16932 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16933 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16934 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16935 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16936 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16937 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16938 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16939
16940 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16941 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16942 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16943 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16944
16945 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016946 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016947 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16948
16949 { } /* end */
16950};
16951
16952/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016953static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016954{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016955 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016956
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016957 spec->autocfg.hp_pins[0] = 0x15;
16958 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016959 spec->automute = 1;
16960 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +020016961}
16962
Takashi Iwaicb53c622007-08-10 17:21:45 +020016963#ifdef CONFIG_SND_HDA_POWER_SAVE
16964#define alc861vd_loopbacks alc880_loopbacks
16965#endif
16966
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016967/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016968#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16969#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16970#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16971#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16972
16973/*
16974 * configuration and preset
16975 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016976static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016977 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016978 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016979 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016980 [ALC861VD_3ST] = "3stack",
16981 [ALC861VD_3ST_DIG] = "3stack-digout",
16982 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016983 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016984 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016985 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016986 [ALC861VD_AUTO] = "auto",
16987};
16988
Takashi Iwaia9111322011-05-02 11:30:18 +020016989static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016990 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16991 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016992 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016993 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016994 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016995 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016996 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016997 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016998 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016999 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020017000 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010017001 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020017002 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017003 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020017004 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017005 {}
17006};
17007
Takashi Iwaia9111322011-05-02 11:30:18 +020017008static const struct alc_config_preset alc861vd_presets[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017009 [ALC660VD_3ST] = {
17010 .mixers = { alc861vd_3st_mixer },
17011 .init_verbs = { alc861vd_volume_init_verbs,
17012 alc861vd_3stack_init_verbs },
17013 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17014 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017015 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17016 .channel_mode = alc861vd_3stack_2ch_modes,
17017 .input_mux = &alc861vd_capture_source,
17018 },
Mike Crash6963f842007-06-25 12:12:51 +020017019 [ALC660VD_3ST_DIG] = {
17020 .mixers = { alc861vd_3st_mixer },
17021 .init_verbs = { alc861vd_volume_init_verbs,
17022 alc861vd_3stack_init_verbs },
17023 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17024 .dac_nids = alc660vd_dac_nids,
17025 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020017026 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17027 .channel_mode = alc861vd_3stack_2ch_modes,
17028 .input_mux = &alc861vd_capture_source,
17029 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017030 [ALC861VD_3ST] = {
17031 .mixers = { alc861vd_3st_mixer },
17032 .init_verbs = { alc861vd_volume_init_verbs,
17033 alc861vd_3stack_init_verbs },
17034 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17035 .dac_nids = alc861vd_dac_nids,
17036 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17037 .channel_mode = alc861vd_3stack_2ch_modes,
17038 .input_mux = &alc861vd_capture_source,
17039 },
17040 [ALC861VD_3ST_DIG] = {
17041 .mixers = { alc861vd_3st_mixer },
17042 .init_verbs = { alc861vd_volume_init_verbs,
17043 alc861vd_3stack_init_verbs },
17044 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17045 .dac_nids = alc861vd_dac_nids,
17046 .dig_out_nid = ALC861VD_DIGOUT_NID,
17047 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17048 .channel_mode = alc861vd_3stack_2ch_modes,
17049 .input_mux = &alc861vd_capture_source,
17050 },
17051 [ALC861VD_6ST_DIG] = {
17052 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
17053 .init_verbs = { alc861vd_volume_init_verbs,
17054 alc861vd_6stack_init_verbs },
17055 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17056 .dac_nids = alc861vd_dac_nids,
17057 .dig_out_nid = ALC861VD_DIGOUT_NID,
17058 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
17059 .channel_mode = alc861vd_6stack_modes,
17060 .input_mux = &alc861vd_capture_source,
17061 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020017062 [ALC861VD_LENOVO] = {
17063 .mixers = { alc861vd_lenovo_mixer },
17064 .init_verbs = { alc861vd_volume_init_verbs,
17065 alc861vd_3stack_init_verbs,
17066 alc861vd_eapd_verbs,
17067 alc861vd_lenovo_unsol_verbs },
17068 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17069 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017070 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17071 .channel_mode = alc861vd_3stack_2ch_modes,
17072 .input_mux = &alc861vd_capture_source,
17073 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017074 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017075 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017076 },
Kailang Yang272a5272007-05-14 11:00:38 +020017077 [ALC861VD_DALLAS] = {
17078 .mixers = { alc861vd_dallas_mixer },
17079 .init_verbs = { alc861vd_dallas_verbs },
17080 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17081 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020017082 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17083 .channel_mode = alc861vd_3stack_2ch_modes,
17084 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020017085 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017086 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020017087 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017088 },
17089 [ALC861VD_HP] = {
17090 .mixers = { alc861vd_hp_mixer },
17091 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
17092 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
17093 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017094 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020017095 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17096 .channel_mode = alc861vd_3stack_2ch_modes,
17097 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020017098 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017099 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020017100 .init_hook = alc_hp_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020017101 },
Takashi Iwai13c94742008-11-05 08:06:08 +010017102 [ALC660VD_ASUS_V1S] = {
17103 .mixers = { alc861vd_lenovo_mixer },
17104 .init_verbs = { alc861vd_volume_init_verbs,
17105 alc861vd_3stack_init_verbs,
17106 alc861vd_eapd_verbs,
17107 alc861vd_lenovo_unsol_verbs },
17108 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
17109 .dac_nids = alc660vd_dac_nids,
17110 .dig_out_nid = ALC861VD_DIGOUT_NID,
17111 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
17112 .channel_mode = alc861vd_3stack_2ch_modes,
17113 .input_mux = &alc861vd_capture_source,
17114 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017115 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020017116 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010017117 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017118};
17119
17120/*
17121 * BIOS auto configuration
17122 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020017123static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
17124 const struct auto_pin_cfg *cfg)
17125{
Herton Ronaldo Krzesinski71675942010-11-25 00:08:01 -020017126 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020017127}
17128
17129
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017130static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
17131 hda_nid_t nid, int pin_type, int dac_idx)
17132{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017133 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017134}
17135
17136static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
17137{
17138 struct alc_spec *spec = codec->spec;
17139 int i;
17140
17141 for (i = 0; i <= HDA_SIDE; i++) {
17142 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017143 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017144 if (nid)
17145 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020017146 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017147 }
17148}
17149
17150
17151static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
17152{
17153 struct alc_spec *spec = codec->spec;
17154 hda_nid_t pin;
17155
17156 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040017157 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017158 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017159 pin = spec->autocfg.speaker_pins[0];
17160 if (pin)
17161 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017162}
17163
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017164#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
17165
17166static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
17167{
17168 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017169 struct auto_pin_cfg *cfg = &spec->autocfg;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017170 int i;
17171
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017172 for (i = 0; i < cfg->num_inputs; i++) {
17173 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017174 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020017175 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +010017176 if (nid != ALC861VD_PIN_CD_NID &&
17177 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017178 snd_hda_codec_write(codec, nid, 0,
17179 AC_VERB_SET_AMP_GAIN_MUTE,
17180 AMP_OUT_MUTE);
17181 }
17182 }
17183}
17184
Takashi Iwaif511b012008-08-15 16:46:42 +020017185#define alc861vd_auto_init_input_src alc882_auto_init_input_src
17186
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017187#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
17188#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
17189
17190/* add playback controls from the parsed DAC table */
Takashi Iwai569ed342011-01-19 10:14:46 +010017191/* Based on ALC880 version. But ALC861VD has separate,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017192 * different NIDs for mute/unmute switch and volume control */
17193static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
17194 const struct auto_pin_cfg *cfg)
17195{
Takashi Iwaiea734962011-01-17 11:29:34 +010017196 static const char * const chname[4] = {
17197 "Front", "Surround", "CLFE", "Side"
17198 };
Takashi Iwaice764ab2011-04-27 16:35:23 +020017199 const char *pfx = alc_get_line_out_pfx(spec, true);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017200 hda_nid_t nid_v, nid_s;
Takashi Iwaice764ab2011-04-27 16:35:23 +020017201 int i, err, noutputs;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017202
Takashi Iwaice764ab2011-04-27 16:35:23 +020017203 noutputs = cfg->line_outs;
17204 if (spec->multi_ios > 0)
17205 noutputs += spec->multi_ios;
17206
17207 for (i = 0; i < noutputs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017208 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017209 continue;
17210 nid_v = alc861vd_idx_to_mixer_vol(
17211 alc880_dac_to_idx(
17212 spec->multiout.dac_nids[i]));
17213 nid_s = alc861vd_idx_to_mixer_switch(
17214 alc880_dac_to_idx(
17215 spec->multiout.dac_nids[i]));
17216
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017217 if (!pfx && i == 2) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017218 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017219 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17220 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017221 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
17222 HDA_OUTPUT));
17223 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017224 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017225 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17226 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017227 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
17228 HDA_OUTPUT));
17229 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017230 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017231 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17232 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017233 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
17234 HDA_INPUT));
17235 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017236 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017237 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17238 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017239 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
17240 HDA_INPUT));
17241 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017242 return err;
17243 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017244 const char *name = pfx;
David Henningsson5a882642011-03-23 08:35:07 +010017245 int index = i;
17246 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017247 name = chname[i];
David Henningsson5a882642011-03-23 08:35:07 +010017248 index = 0;
17249 }
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017250 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
David Henningsson5a882642011-03-23 08:35:07 +010017251 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017252 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
17253 HDA_OUTPUT));
17254 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017255 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010017256 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
David Henningsson5a882642011-03-23 08:35:07 +010017257 name, index,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017258 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017259 HDA_INPUT));
17260 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017261 return err;
17262 }
17263 }
17264 return 0;
17265}
17266
17267/* add playback controls for speaker and HP outputs */
17268/* Based on ALC880 version. But ALC861VD has separate,
17269 * different NIDs for mute/unmute switch and volume control */
17270static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
17271 hda_nid_t pin, const char *pfx)
17272{
17273 hda_nid_t nid_v, nid_s;
17274 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017275
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017276 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017277 return 0;
17278
17279 if (alc880_is_fixed_pin(pin)) {
17280 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
17281 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017282 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017283 spec->multiout.hp_nid = nid_v;
17284 else
17285 spec->multiout.extra_out_nid[0] = nid_v;
17286 /* control HP volume/switch on the output mixer amp */
17287 nid_v = alc861vd_idx_to_mixer_vol(
17288 alc880_fixed_pin_idx(pin));
17289 nid_s = alc861vd_idx_to_mixer_switch(
17290 alc880_fixed_pin_idx(pin));
17291
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017292 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017293 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
17294 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017295 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017296 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017297 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
17298 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017299 return err;
17300 } else if (alc880_is_multi_pin(pin)) {
17301 /* set manual connection */
17302 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017303 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017304 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17305 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017306 return err;
17307 }
17308 return 0;
17309}
17310
17311/* parse the BIOS configuration and set up the alc_spec
17312 * return 1 if successful, 0 if the proper config is not found,
17313 * or a negative error code
17314 * Based on ALC880 version - had to change it to override
17315 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
17316static int alc861vd_parse_auto_config(struct hda_codec *codec)
17317{
17318 struct alc_spec *spec = codec->spec;
17319 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017320 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017321
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017322 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17323 alc861vd_ignore);
17324 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017325 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017326 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017327 return 0; /* can't find valid BIOS pin config */
17328
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017329 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17330 if (err < 0)
17331 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020017332 err = alc_auto_add_multi_channel_mode(codec);
17333 if (err < 0)
17334 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017335 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
17336 if (err < 0)
17337 return err;
17338 err = alc861vd_auto_create_extra_out(spec,
17339 spec->autocfg.speaker_pins[0],
17340 "Speaker");
17341 if (err < 0)
17342 return err;
17343 err = alc861vd_auto_create_extra_out(spec,
17344 spec->autocfg.hp_pins[0],
17345 "Headphone");
17346 if (err < 0)
17347 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017348 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017349 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017350 return err;
17351
17352 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17353
Takashi Iwai757899a2010-07-30 10:48:14 +020017354 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017355
Takashi Iwai603c4012008-07-30 15:01:44 +020017356 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017357 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017358
Takashi Iwaid88897e2008-10-31 15:01:37 +010017359 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017360
17361 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017362 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017363
Takashi Iwai776e1842007-08-29 15:07:11 +020017364 err = alc_auto_add_mic_boost(codec);
17365 if (err < 0)
17366 return err;
17367
Kailang Yang6227cdc2010-02-25 08:36:52 +010017368 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017369
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017370 return 1;
17371}
17372
17373/* additional initialization for auto-configuration model */
17374static void alc861vd_auto_init(struct hda_codec *codec)
17375{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017376 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017377 alc861vd_auto_init_multi_out(codec);
17378 alc861vd_auto_init_hp_out(codec);
17379 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017380 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020017381 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017382 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017383 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017384}
17385
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017386enum {
17387 ALC660VD_FIX_ASUS_GPIO1
17388};
17389
17390/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017391static const struct alc_fixup alc861vd_fixups[] = {
17392 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017393 .type = ALC_FIXUP_VERBS,
17394 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020017395 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
17396 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
17397 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
17398 { }
17399 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017400 },
17401};
17402
Takashi Iwaia9111322011-05-02 11:30:18 +020017403static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017404 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
17405 {}
17406};
17407
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017408static int patch_alc861vd(struct hda_codec *codec)
17409{
17410 struct alc_spec *spec;
17411 int err, board_config;
17412
17413 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17414 if (spec == NULL)
17415 return -ENOMEM;
17416
17417 codec->spec = spec;
17418
17419 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
17420 alc861vd_models,
17421 alc861vd_cfg_tbl);
17422
17423 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017424 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17425 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017426 board_config = ALC861VD_AUTO;
17427 }
17428
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017429 if (board_config == ALC861VD_AUTO) {
17430 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
17431 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
17432 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017433
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017434 if (board_config == ALC861VD_AUTO) {
17435 /* automatic parse from the BIOS config */
17436 err = alc861vd_parse_auto_config(codec);
17437 if (err < 0) {
17438 alc_free(codec);
17439 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017440 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017441 printk(KERN_INFO
17442 "hda_codec: Cannot set up configuration "
17443 "from BIOS. Using base mode...\n");
17444 board_config = ALC861VD_3ST;
17445 }
17446 }
17447
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017448 err = snd_hda_attach_beep_device(codec, 0x23);
17449 if (err < 0) {
17450 alc_free(codec);
17451 return err;
17452 }
17453
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017454 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017455 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017456
Kailang Yang2f893282008-05-27 12:14:47 +020017457 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020017458 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010017459 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020017460 }
17461
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017462 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
17463 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
17464
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017465 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
17466 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
17467
Takashi Iwaidd704692009-08-11 08:45:11 +020017468 if (!spec->adc_nids) {
17469 spec->adc_nids = alc861vd_adc_nids;
17470 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
17471 }
17472 if (!spec->capsrc_nids)
17473 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017474
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017475 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010017476 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017477
Takashi Iwai2134ea42008-01-10 16:53:55 +010017478 spec->vmaster_nid = 0x02;
17479
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010017480 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017481
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017482 codec->patch_ops = alc_patch_ops;
17483
17484 if (board_config == ALC861VD_AUTO)
17485 spec->init_hook = alc861vd_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020017486 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017487#ifdef CONFIG_SND_HDA_POWER_SAVE
17488 if (!spec->loopback.amplist)
17489 spec->loopback.amplist = alc861vd_loopbacks;
17490#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017491
17492 return 0;
17493}
17494
17495/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017496 * ALC662 support
17497 *
17498 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
17499 * configuration. Each pin widget can choose any input DACs and a mixer.
17500 * Each ADC is connected from a mixer of all inputs. This makes possible
17501 * 6-channel independent captures.
17502 *
17503 * In addition, an independent DAC for the multi-playback (not used in this
17504 * driver yet).
17505 */
17506#define ALC662_DIGOUT_NID 0x06
17507#define ALC662_DIGIN_NID 0x0a
17508
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017509static const hda_nid_t alc662_dac_nids[3] = {
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080017510 /* front, rear, clfe */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017511 0x02, 0x03, 0x04
17512};
17513
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017514static const hda_nid_t alc272_dac_nids[2] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017515 0x02, 0x03
17516};
17517
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017518static const hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017519 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017520 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017521};
Takashi Iwaie1406342008-02-11 18:32:32 +010017522
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017523static const hda_nid_t alc272_adc_nids[1] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017524 /* ADC1-2 */
17525 0x08,
17526};
17527
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020017528static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
17529static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017530
Takashi Iwaie1406342008-02-11 18:32:32 +010017531
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017532/* input MUX */
17533/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020017534static const struct hda_input_mux alc662_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017535 .num_items = 4,
17536 .items = {
17537 { "Mic", 0x0 },
17538 { "Front Mic", 0x1 },
17539 { "Line", 0x2 },
17540 { "CD", 0x4 },
17541 },
17542};
17543
Takashi Iwaia9111322011-05-02 11:30:18 +020017544static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017545 .num_items = 2,
17546 .items = {
17547 { "Mic", 0x1 },
17548 { "Line", 0x2 },
17549 },
17550};
Kailang Yang291702f2007-10-16 14:28:03 +020017551
Takashi Iwaia9111322011-05-02 11:30:18 +020017552static const struct hda_input_mux alc663_capture_source = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017553 .num_items = 3,
17554 .items = {
17555 { "Mic", 0x0 },
17556 { "Front Mic", 0x1 },
17557 { "Line", 0x2 },
17558 },
17559};
17560
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017561#if 0 /* set to 1 for testing other input sources below */
Takashi Iwaia9111322011-05-02 11:30:18 +020017562static const struct hda_input_mux alc272_nc10_capture_source = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020017563 .num_items = 16,
17564 .items = {
17565 { "Autoselect Mic", 0x0 },
17566 { "Internal Mic", 0x1 },
17567 { "In-0x02", 0x2 },
17568 { "In-0x03", 0x3 },
17569 { "In-0x04", 0x4 },
17570 { "In-0x05", 0x5 },
17571 { "In-0x06", 0x6 },
17572 { "In-0x07", 0x7 },
17573 { "In-0x08", 0x8 },
17574 { "In-0x09", 0x9 },
17575 { "In-0x0a", 0x0a },
17576 { "In-0x0b", 0x0b },
17577 { "In-0x0c", 0x0c },
17578 { "In-0x0d", 0x0d },
17579 { "In-0x0e", 0x0e },
17580 { "In-0x0f", 0x0f },
17581 },
17582};
17583#endif
17584
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017585/*
17586 * 2ch mode
17587 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017588static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017589 { 2, NULL }
17590};
17591
17592/*
17593 * 2ch mode
17594 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017595static const struct hda_verb alc662_3ST_ch2_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017596 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17597 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17598 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17599 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17600 { } /* end */
17601};
17602
17603/*
17604 * 6ch mode
17605 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017606static const struct hda_verb alc662_3ST_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017607 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17608 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17609 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17610 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17611 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17612 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17613 { } /* end */
17614};
17615
Takashi Iwaia9111322011-05-02 11:30:18 +020017616static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017617 { 2, alc662_3ST_ch2_init },
17618 { 6, alc662_3ST_ch6_init },
17619};
17620
17621/*
17622 * 2ch mode
17623 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017624static const struct hda_verb alc662_sixstack_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017625 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17626 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17627 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17628 { } /* end */
17629};
17630
17631/*
17632 * 6ch mode
17633 */
Takashi Iwaia9111322011-05-02 11:30:18 +020017634static const struct hda_verb alc662_sixstack_ch8_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017635 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17636 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17637 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17638 { } /* end */
17639};
17640
Takashi Iwaia9111322011-05-02 11:30:18 +020017641static const struct hda_channel_mode alc662_5stack_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017642 { 2, alc662_sixstack_ch6_init },
17643 { 6, alc662_sixstack_ch8_init },
17644};
17645
17646/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17647 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17648 */
17649
Takashi Iwaia9111322011-05-02 11:30:18 +020017650static const struct snd_kcontrol_new alc662_base_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017651 /* output mixer control */
17652 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017653 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017654 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017655 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017656 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17657 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017658 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17659 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017660 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17661
17662 /*Input mixer control */
17663 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17664 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17665 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17666 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17667 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17668 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17669 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17670 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017671 { } /* end */
17672};
17673
Takashi Iwaia9111322011-05-02 11:30:18 +020017674static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017675 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017676 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017677 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17678 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17679 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17680 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17681 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17682 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17683 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17684 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17685 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017686 { } /* end */
17687};
17688
Takashi Iwaia9111322011-05-02 11:30:18 +020017689static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017690 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017691 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017692 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017693 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017694 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17695 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017696 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17697 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017698 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17699 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17700 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17701 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17702 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17703 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17704 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17705 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17706 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017707 { } /* end */
17708};
17709
Takashi Iwaia9111322011-05-02 11:30:18 +020017710static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017711 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17712 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017713 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17714 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017715 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17716 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17717 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17718 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17719 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017720 { } /* end */
17721};
17722
Takashi Iwaia9111322011-05-02 11:30:18 +020017723static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017724 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17725 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017726
David Henningsson5f99f862011-01-04 15:24:24 +010017727 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017728 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17729 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017730
David Henningsson5f99f862011-01-04 15:24:24 +010017731 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017732 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17733 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017734 { } /* end */
17735};
17736
Takashi Iwaia9111322011-05-02 11:30:18 +020017737static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017738 ALC262_HIPPO_MASTER_SWITCH,
17739 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017740 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017741 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17742 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017743 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17744 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17745 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17746 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17747 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17748 { } /* end */
17749};
17750
Takashi Iwaia9111322011-05-02 11:30:18 +020017751static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017752 .ops = &snd_hda_bind_vol,
17753 .values = {
17754 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17755 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17756 0
17757 },
17758};
17759
Takashi Iwaia9111322011-05-02 11:30:18 +020017760static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017761 .ops = &snd_hda_bind_sw,
17762 .values = {
17763 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17764 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17765 0
17766 },
17767};
17768
Takashi Iwaia9111322011-05-02 11:30:18 +020017769static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017770 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17771 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17772 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17773 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17774 { } /* end */
17775};
17776
Takashi Iwaia9111322011-05-02 11:30:18 +020017777static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017778 .ops = &snd_hda_bind_sw,
17779 .values = {
17780 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17781 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17782 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17783 0
17784 },
17785};
17786
Takashi Iwaia9111322011-05-02 11:30:18 +020017787static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017788 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17789 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17790 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17791 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17792 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17793 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17794
17795 { } /* end */
17796};
17797
Takashi Iwaia9111322011-05-02 11:30:18 +020017798static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017799 .ops = &snd_hda_bind_sw,
17800 .values = {
17801 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17802 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17803 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17804 0
17805 },
17806};
17807
Takashi Iwaia9111322011-05-02 11:30:18 +020017808static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017809 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17810 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17811 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17812 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17813 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17814 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17815 { } /* end */
17816};
17817
Takashi Iwaia9111322011-05-02 11:30:18 +020017818static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017819 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17820 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017821 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17822 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17823 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17824 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17825 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17826 { } /* end */
17827};
17828
Takashi Iwaia9111322011-05-02 11:30:18 +020017829static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017830 .ops = &snd_hda_bind_vol,
17831 .values = {
17832 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17833 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17834 0
17835 },
17836};
17837
Takashi Iwaia9111322011-05-02 11:30:18 +020017838static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017839 .ops = &snd_hda_bind_sw,
17840 .values = {
17841 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17842 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17843 0
17844 },
17845};
17846
Takashi Iwaia9111322011-05-02 11:30:18 +020017847static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017848 HDA_BIND_VOL("Master Playback Volume",
17849 &alc663_asus_two_bind_master_vol),
17850 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17851 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017852 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17853 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17854 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017855 { } /* end */
17856};
17857
Takashi Iwaia9111322011-05-02 11:30:18 +020017858static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017859 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17860 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17861 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17862 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17863 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17864 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017865 { } /* end */
17866};
17867
Takashi Iwaia9111322011-05-02 11:30:18 +020017868static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017869 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17870 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17871 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17872 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17873 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17874
17875 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17876 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017877 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17878 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017879 { } /* end */
17880};
17881
Takashi Iwaia9111322011-05-02 11:30:18 +020017882static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017883 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17884 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17885 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17886
17887 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17888 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017889 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17890 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017891 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17892 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17893 { } /* end */
17894};
17895
Takashi Iwaia9111322011-05-02 11:30:18 +020017896static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017897 .ops = &snd_hda_bind_sw,
17898 .values = {
17899 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17900 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17901 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17902 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17903 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17904 0
17905 },
17906};
17907
Takashi Iwaia9111322011-05-02 11:30:18 +020017908static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017909 .ops = &snd_hda_bind_sw,
17910 .values = {
17911 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17912 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17913 0
17914 },
17915};
17916
Takashi Iwaia9111322011-05-02 11:30:18 +020017917static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017918 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17919 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17920 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17921 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17922 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17923 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17924 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17925 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17926 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17927 { } /* end */
17928};
17929
Takashi Iwaia9111322011-05-02 11:30:18 +020017930static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017931 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17932 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17933 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17934 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17935 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17936 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17937 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17938 { } /* end */
17939};
17940
17941
Takashi Iwaia9111322011-05-02 11:30:18 +020017942static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017943 {
17944 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17945 .name = "Channel Mode",
17946 .info = alc_ch_mode_info,
17947 .get = alc_ch_mode_get,
17948 .put = alc_ch_mode_put,
17949 },
17950 { } /* end */
17951};
17952
Takashi Iwaia9111322011-05-02 11:30:18 +020017953static const struct hda_verb alc662_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017954 /* ADC: mute amp left and right */
17955 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17956 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017957
Kailang Yangb60dd392007-09-20 12:50:29 +020017958 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17959 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17960 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17961 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17962 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17963 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017964
17965 /* Front Pin: output 0 (0x0c) */
17966 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17967 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17968
17969 /* Rear Pin: output 1 (0x0d) */
17970 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17971 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17972
17973 /* CLFE Pin: output 2 (0x0e) */
17974 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17975 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17976
17977 /* Mic (rear) pin: input vref at 80% */
17978 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17979 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17980 /* Front Mic pin: input vref at 80% */
17981 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17982 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17983 /* Line In pin: input */
17984 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17985 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17986 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17987 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17988 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17989 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17990 /* CD pin widget for input */
17991 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17992
17993 /* FIXME: use matrix-type input source selection */
17994 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17995 /* Input mixer */
17996 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017997 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017998
Takashi Iwaia7f23712011-04-07 10:24:23 +020017999 { }
18000};
18001
Takashi Iwaia9111322011-05-02 11:30:18 +020018002static const struct hda_verb alc662_eapd_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020018003 /* always trun on EAPD */
18004 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
18005 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018006 { }
18007};
18008
Takashi Iwaia9111322011-05-02 11:30:18 +020018009static const struct hda_verb alc662_sue_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018010 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
18011 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020018012 {}
18013};
18014
Takashi Iwaia9111322011-05-02 11:30:18 +020018015static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020018016 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18017 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18018 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018019};
18020
Kailang Yang8c427222008-01-10 13:03:59 +010018021/* Set Unsolicited Event*/
Takashi Iwaia9111322011-05-02 11:30:18 +020018022static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010018023 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18024 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18025 {}
18026};
18027
Takashi Iwaia9111322011-05-02 11:30:18 +020018028static const struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018029 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18030 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020018031 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18032 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020018033 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18034 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18035 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020018036 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18037 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18038 {}
18039};
18040
Takashi Iwaia9111322011-05-02 11:30:18 +020018041static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018042 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18043 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18044 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18045 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18046 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18047 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18048 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18049 {}
18050};
18051
Takashi Iwaia9111322011-05-02 11:30:18 +020018052static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018053 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18054 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18055 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18056 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18057 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18058 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18059 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18060 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18061 {}
18062};
18063
Takashi Iwaia9111322011-05-02 11:30:18 +020018064static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018065 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18067 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18068 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18069 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18070 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18071 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18072 {}
18073};
18074
Takashi Iwaia9111322011-05-02 11:30:18 +020018075static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018076 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18077 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18078 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18079 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18080 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18081 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18082 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
18083 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18084 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18085 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18086 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18087 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18088 {}
18089};
18090
Takashi Iwaia9111322011-05-02 11:30:18 +020018091static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018092 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18093 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18094 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18095 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18096 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18097 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18098 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18099 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18100 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
18101 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18102 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18103 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18104 {}
18105};
18106
Takashi Iwaia9111322011-05-02 11:30:18 +020018107static const struct hda_verb alc663_g71v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020018108 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18109 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
18110 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
18111
18112 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18113 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18114 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18115
18116 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
18117 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
18118 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
18119 {}
18120};
18121
Takashi Iwaia9111322011-05-02 11:30:18 +020018122static const struct hda_verb alc663_g50v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020018123 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18124 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18125 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
18126
18127 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18128 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18129 {}
18130};
18131
Takashi Iwaia9111322011-05-02 11:30:18 +020018132static const struct hda_verb alc662_ecs_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018133 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
18134 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18135 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18136 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18137 {}
18138};
18139
Takashi Iwaia9111322011-05-02 11:30:18 +020018140static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020018141 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18142 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18143 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18144 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18145 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18146 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18147 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18148 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18149 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18150 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18151 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18152 {}
18153};
18154
Takashi Iwaia9111322011-05-02 11:30:18 +020018155static const struct hda_verb alc272_dell_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020018156 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18157 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18158 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18159 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18160 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18161 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18162 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18163 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18164 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18165 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18166 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18167 {}
18168};
18169
Takashi Iwaia9111322011-05-02 11:30:18 +020018170static const struct hda_verb alc663_mode7_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010018171 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18172 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18173 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18174 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18175 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18176 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18177 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
18178 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18179 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18180 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18181 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18182 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18183 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18184 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18185 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18186 {}
18187};
18188
Takashi Iwaia9111322011-05-02 11:30:18 +020018189static const struct hda_verb alc663_mode8_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010018190 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18191 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18192 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18193 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
18194 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18195 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18196 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18197 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18198 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18199 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18200 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18201 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18202 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18203 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18204 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18205 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18206 {}
18207};
18208
Takashi Iwaia9111322011-05-02 11:30:18 +020018209static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018210 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
18211 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
18212 { } /* end */
18213};
18214
Takashi Iwaia9111322011-05-02 11:30:18 +020018215static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020018216 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
18217 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
18218 { } /* end */
18219};
18220
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018221static void alc662_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018222{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018223 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018224
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018225 spec->autocfg.hp_pins[0] = 0x1b;
18226 spec->autocfg.line_out_pins[0] = 0x14;
18227 spec->autocfg.speaker_pins[0] = 0x15;
18228 spec->automute = 1;
18229 spec->detect_line = 1;
18230 spec->automute_lines = 1;
18231 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018232}
18233
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018234static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020018235{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018236 struct alc_spec *spec = codec->spec;
18237
18238 alc262_hippo1_setup(codec);
18239 spec->ext_mic.pin = 0x18;
18240 spec->ext_mic.mux_idx = 0;
18241 spec->int_mic.pin = 0x19;
18242 spec->int_mic.mux_idx = 1;
18243 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020018244}
18245
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018246static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010018247{
Takashi Iwai42171c12009-05-08 14:11:43 +020018248 struct alc_spec *spec = codec->spec;
18249
18250 spec->autocfg.hp_pins[0] = 0x14;
18251 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaie9427962011-04-28 15:46:07 +020018252 spec->automute = 1;
18253 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang8c427222008-01-10 13:03:59 +010018254}
18255
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018256static void alc663_m51va_setup(struct hda_codec *codec)
18257{
18258 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018259 spec->autocfg.hp_pins[0] = 0x21;
18260 spec->autocfg.speaker_pins[0] = 0x14;
18261 spec->automute_mixer_nid[0] = 0x0c;
18262 spec->automute = 1;
18263 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018264 spec->ext_mic.pin = 0x18;
18265 spec->ext_mic.mux_idx = 0;
18266 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018267 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018268 spec->auto_mic = 1;
18269}
18270
Kailang Yangf1d4e282008-08-26 14:03:29 +020018271/* ***************** Mode1 ******************************/
Kailang Yangebb83ee2009-12-17 12:23:00 +010018272static void alc663_mode1_setup(struct hda_codec *codec)
18273{
18274 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018275 spec->autocfg.hp_pins[0] = 0x21;
18276 spec->autocfg.speaker_pins[0] = 0x14;
18277 spec->automute_mixer_nid[0] = 0x0c;
18278 spec->automute = 1;
18279 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018280 spec->ext_mic.pin = 0x18;
18281 spec->ext_mic.mux_idx = 0;
18282 spec->int_mic.pin = 0x19;
18283 spec->int_mic.mux_idx = 1;
18284 spec->auto_mic = 1;
18285}
18286
Kailang Yangf1d4e282008-08-26 14:03:29 +020018287/* ***************** Mode2 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018288static void alc662_mode2_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018289{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018290 struct alc_spec *spec = codec->spec;
18291 spec->autocfg.hp_pins[0] = 0x1b;
18292 spec->autocfg.speaker_pins[0] = 0x14;
18293 spec->automute = 1;
18294 spec->automute_mode = ALC_AUTOMUTE_PIN;
18295 spec->ext_mic.pin = 0x18;
18296 spec->ext_mic.mux_idx = 0;
18297 spec->int_mic.pin = 0x19;
18298 spec->int_mic.mux_idx = 1;
18299 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018300}
18301
Kailang Yangf1d4e282008-08-26 14:03:29 +020018302/* ***************** Mode3 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018303static void alc663_mode3_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018304{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018305 struct alc_spec *spec = codec->spec;
18306 spec->autocfg.hp_pins[0] = 0x21;
18307 spec->autocfg.hp_pins[0] = 0x15;
18308 spec->autocfg.speaker_pins[0] = 0x14;
18309 spec->automute = 1;
18310 spec->automute_mode = ALC_AUTOMUTE_PIN;
18311 spec->ext_mic.pin = 0x18;
18312 spec->ext_mic.mux_idx = 0;
18313 spec->int_mic.pin = 0x19;
18314 spec->int_mic.mux_idx = 1;
18315 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018316}
18317
Kailang Yangf1d4e282008-08-26 14:03:29 +020018318/* ***************** Mode4 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018319static void alc663_mode4_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018320{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018321 struct alc_spec *spec = codec->spec;
18322 spec->autocfg.hp_pins[0] = 0x21;
18323 spec->autocfg.speaker_pins[0] = 0x14;
18324 spec->autocfg.speaker_pins[1] = 0x16;
18325 spec->automute_mixer_nid[0] = 0x0c;
18326 spec->automute_mixer_nid[1] = 0x0e;
18327 spec->automute = 1;
18328 spec->automute_mode = ALC_AUTOMUTE_MIXER;
18329 spec->ext_mic.pin = 0x18;
18330 spec->ext_mic.mux_idx = 0;
18331 spec->int_mic.pin = 0x19;
18332 spec->int_mic.mux_idx = 1;
18333 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018334}
18335
Kailang Yangf1d4e282008-08-26 14:03:29 +020018336/* ***************** Mode5 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018337static void alc663_mode5_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018338{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018339 struct alc_spec *spec = codec->spec;
18340 spec->autocfg.hp_pins[0] = 0x15;
18341 spec->autocfg.speaker_pins[0] = 0x14;
18342 spec->autocfg.speaker_pins[1] = 0x16;
18343 spec->automute_mixer_nid[0] = 0x0c;
18344 spec->automute_mixer_nid[1] = 0x0e;
18345 spec->automute = 1;
18346 spec->automute_mode = ALC_AUTOMUTE_MIXER;
18347 spec->ext_mic.pin = 0x18;
18348 spec->ext_mic.mux_idx = 0;
18349 spec->int_mic.pin = 0x19;
18350 spec->int_mic.mux_idx = 1;
18351 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018352}
18353
Kailang Yangf1d4e282008-08-26 14:03:29 +020018354/* ***************** Mode6 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018355static void alc663_mode6_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020018356{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018357 struct alc_spec *spec = codec->spec;
18358 spec->autocfg.hp_pins[0] = 0x1b;
18359 spec->autocfg.hp_pins[0] = 0x15;
18360 spec->autocfg.speaker_pins[0] = 0x14;
18361 spec->automute_mixer_nid[0] = 0x0c;
18362 spec->automute = 1;
18363 spec->automute_mode = ALC_AUTOMUTE_MIXER;
18364 spec->ext_mic.pin = 0x18;
18365 spec->ext_mic.mux_idx = 0;
18366 spec->int_mic.pin = 0x19;
18367 spec->int_mic.mux_idx = 1;
18368 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018369}
18370
Kailang Yangebb83ee2009-12-17 12:23:00 +010018371/* ***************** Mode7 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018372static void alc663_mode7_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010018373{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018374 struct alc_spec *spec = codec->spec;
18375 spec->autocfg.hp_pins[0] = 0x1b;
18376 spec->autocfg.hp_pins[0] = 0x21;
18377 spec->autocfg.speaker_pins[0] = 0x14;
18378 spec->autocfg.speaker_pins[0] = 0x17;
18379 spec->automute = 1;
18380 spec->automute_mode = ALC_AUTOMUTE_PIN;
18381 spec->ext_mic.pin = 0x18;
18382 spec->ext_mic.mux_idx = 0;
18383 spec->int_mic.pin = 0x19;
18384 spec->int_mic.mux_idx = 1;
18385 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018386}
18387
18388/* ***************** Mode8 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018389static void alc663_mode8_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010018390{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018391 struct alc_spec *spec = codec->spec;
18392 spec->autocfg.hp_pins[0] = 0x21;
18393 spec->autocfg.hp_pins[1] = 0x15;
18394 spec->autocfg.speaker_pins[0] = 0x14;
18395 spec->autocfg.speaker_pins[0] = 0x17;
18396 spec->automute = 1;
18397 spec->automute_mode = ALC_AUTOMUTE_PIN;
18398 spec->ext_mic.pin = 0x18;
18399 spec->ext_mic.mux_idx = 0;
18400 spec->int_mic.pin = 0x12;
18401 spec->int_mic.mux_idx = 9;
18402 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018403}
18404
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018405static void alc663_g71v_setup(struct hda_codec *codec)
Kailang Yang6dda9f42008-05-27 12:05:31 +020018406{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018407 struct alc_spec *spec = codec->spec;
18408 spec->autocfg.hp_pins[0] = 0x21;
18409 spec->autocfg.line_out_pins[0] = 0x15;
18410 spec->autocfg.speaker_pins[0] = 0x14;
18411 spec->automute = 1;
18412 spec->automute_mode = ALC_AUTOMUTE_AMP;
18413 spec->detect_line = 1;
18414 spec->automute_lines = 1;
18415 spec->ext_mic.pin = 0x18;
18416 spec->ext_mic.mux_idx = 0;
18417 spec->int_mic.pin = 0x12;
18418 spec->int_mic.mux_idx = 9;
18419 spec->auto_mic = 1;
Kailang Yang6dda9f42008-05-27 12:05:31 +020018420}
18421
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018422#define alc663_g50v_setup alc663_m51va_setup
18423
Takashi Iwaia9111322011-05-02 11:30:18 +020018424static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020018425 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018426 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018427
David Henningsson5f99f862011-01-04 15:24:24 +010018428 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018429 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18430 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018431
David Henningsson5f99f862011-01-04 15:24:24 +010018432 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018433 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18434 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018435 { } /* end */
18436};
18437
Takashi Iwaia9111322011-05-02 11:30:18 +020018438static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020018439 /* Master Playback automatically created from Speaker and Headphone */
18440 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18441 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18442 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18443 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18444
David Henningsson8607f7c2010-12-20 14:43:54 +010018445 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18446 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018447 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018448
David Henningsson28c4edb2010-12-20 14:24:29 +010018449 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18450 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018451 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018452 { } /* end */
18453};
18454
Takashi Iwaicb53c622007-08-10 17:21:45 +020018455#ifdef CONFIG_SND_HDA_POWER_SAVE
18456#define alc662_loopbacks alc880_loopbacks
18457#endif
18458
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018459
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018460/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018461#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18462#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18463#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18464#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18465
18466/*
18467 * configuration and preset
18468 */
Takashi Iwaiea734962011-01-17 11:29:34 +010018469static const char * const alc662_models[ALC662_MODEL_LAST] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018470 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18471 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18472 [ALC662_3ST_6ch] = "3stack-6ch",
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080018473 [ALC662_5ST_DIG] = "5stack-dig",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018474 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018475 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018476 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018477 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018478 [ALC663_ASUS_M51VA] = "m51va",
18479 [ALC663_ASUS_G71V] = "g71v",
18480 [ALC663_ASUS_H13] = "h13",
18481 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018482 [ALC663_ASUS_MODE1] = "asus-mode1",
18483 [ALC662_ASUS_MODE2] = "asus-mode2",
18484 [ALC663_ASUS_MODE3] = "asus-mode3",
18485 [ALC663_ASUS_MODE4] = "asus-mode4",
18486 [ALC663_ASUS_MODE5] = "asus-mode5",
18487 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018488 [ALC663_ASUS_MODE7] = "asus-mode7",
18489 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018490 [ALC272_DELL] = "dell",
18491 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018492 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018493 [ALC662_AUTO] = "auto",
18494};
18495
Takashi Iwaia9111322011-05-02 11:30:18 +020018496static const struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018497 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018498 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18499 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018500 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18501 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018502 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018503 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18504 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18505 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18506 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018507 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18508 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018509 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018510 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18511 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18512 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18513 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18514 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018515 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018516 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18517 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018518 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18519 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18520 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18521 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018522 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018523 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18524 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18525 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018526 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18527 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18528 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18529 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018530 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018531 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18532 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018533 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018534 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18535 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18536 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018537 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018538 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018539 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18540 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018541 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18542 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18543 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018544 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018545 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18546 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018547 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018548 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018549 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018550 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18551 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18552 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018553 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018554 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18555 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018556 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018557 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018558 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018559 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018560 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18561 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018562 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018563 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Takashi Iwaiebb47242011-05-02 10:37:29 +020018564 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18565 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018566 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018567 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018568 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018569 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018570 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018571 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018572 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18573 ALC663_ASUS_H13),
Anisse Astier965b76d2011-02-10 13:14:44 +010018574 SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018575 {}
18576};
18577
Takashi Iwaia9111322011-05-02 11:30:18 +020018578static const struct alc_config_preset alc662_presets[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018579 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018580 .mixers = { alc662_3ST_2ch_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018581 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018582 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18583 .dac_nids = alc662_dac_nids,
18584 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018585 .dig_in_nid = ALC662_DIGIN_NID,
18586 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18587 .channel_mode = alc662_3ST_2ch_modes,
18588 .input_mux = &alc662_capture_source,
18589 },
18590 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018591 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018592 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018593 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18594 .dac_nids = alc662_dac_nids,
18595 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018596 .dig_in_nid = ALC662_DIGIN_NID,
18597 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18598 .channel_mode = alc662_3ST_6ch_modes,
18599 .need_dac_fix = 1,
18600 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018601 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018602 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018603 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018604 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018605 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18606 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018607 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18608 .channel_mode = alc662_3ST_6ch_modes,
18609 .need_dac_fix = 1,
18610 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018611 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018612 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018613 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018614 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018615 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18616 .dac_nids = alc662_dac_nids,
18617 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018618 .dig_in_nid = ALC662_DIGIN_NID,
18619 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18620 .channel_mode = alc662_5stack_modes,
18621 .input_mux = &alc662_capture_source,
18622 },
18623 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018624 .mixers = { alc662_lenovo_101e_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018625 .init_verbs = { alc662_init_verbs,
18626 alc662_eapd_init_verbs,
18627 alc662_sue_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018628 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18629 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018630 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18631 .channel_mode = alc662_3ST_2ch_modes,
18632 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018633 .unsol_event = alc_sku_unsol_event,
18634 .setup = alc662_lenovo_101e_setup,
18635 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018636 },
Kailang Yang291702f2007-10-16 14:28:03 +020018637 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018638 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018639 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018640 alc662_eapd_init_verbs,
Kailang Yang291702f2007-10-16 14:28:03 +020018641 alc662_eeepc_sue_init_verbs },
18642 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18643 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018644 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18645 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020018646 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018647 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018648 .init_hook = alc_inithook,
Kailang Yang291702f2007-10-16 14:28:03 +020018649 },
Kailang Yang8c427222008-01-10 13:03:59 +010018650 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018651 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018652 alc662_chmode_mixer },
18653 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018654 alc662_eapd_init_verbs,
Kailang Yang8c427222008-01-10 13:03:59 +010018655 alc662_eeepc_ep20_sue_init_verbs },
18656 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18657 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018658 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18659 .channel_mode = alc662_3ST_6ch_modes,
18660 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020018661 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018662 .setup = alc662_eeepc_ep20_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018663 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010018664 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018665 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018666 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018667 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018668 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018669 alc662_ecs_init_verbs },
18670 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18671 .dac_nids = alc662_dac_nids,
18672 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18673 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020018674 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018675 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020018676 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018677 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018678 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018679 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018680 .init_verbs = { alc662_init_verbs,
18681 alc662_eapd_init_verbs,
18682 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018683 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18684 .dac_nids = alc662_dac_nids,
18685 .dig_out_nid = ALC662_DIGOUT_NID,
18686 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18687 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018688 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018689 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018690 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018691 },
18692 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018693 .mixers = { alc663_g71v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018694 .init_verbs = { alc662_init_verbs,
18695 alc662_eapd_init_verbs,
18696 alc663_g71v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018697 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18698 .dac_nids = alc662_dac_nids,
18699 .dig_out_nid = ALC662_DIGOUT_NID,
18700 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18701 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018702 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018703 .setup = alc663_g71v_setup,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020018704 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018705 },
18706 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018707 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018708 .init_verbs = { alc662_init_verbs,
18709 alc662_eapd_init_verbs,
18710 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018711 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18712 .dac_nids = alc662_dac_nids,
18713 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18714 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018715 .setup = alc663_m51va_setup,
18716 .unsol_event = alc_sku_unsol_event,
18717 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018718 },
18719 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018720 .mixers = { alc663_g50v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020018721 .init_verbs = { alc662_init_verbs,
18722 alc662_eapd_init_verbs,
18723 alc663_g50v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018724 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18725 .dac_nids = alc662_dac_nids,
18726 .dig_out_nid = ALC662_DIGOUT_NID,
18727 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18728 .channel_mode = alc662_3ST_6ch_modes,
18729 .input_mux = &alc663_capture_source,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018730 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018731 .setup = alc663_g50v_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018732 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018733 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018734 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018735 .mixers = { alc663_m51va_mixer },
18736 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018737 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018738 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018739 alc663_21jd_amic_init_verbs },
18740 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18741 .hp_nid = 0x03,
18742 .dac_nids = alc662_dac_nids,
18743 .dig_out_nid = ALC662_DIGOUT_NID,
18744 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18745 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018746 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018747 .setup = alc663_mode1_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018748 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018749 },
18750 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018751 .mixers = { alc662_1bjd_mixer },
18752 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018753 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018754 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018755 alc662_1bjd_amic_init_verbs },
18756 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18757 .dac_nids = alc662_dac_nids,
18758 .dig_out_nid = ALC662_DIGOUT_NID,
18759 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18760 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018761 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018762 .setup = alc662_mode2_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018763 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018764 },
18765 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018766 .mixers = { alc663_two_hp_m1_mixer },
18767 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018768 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018769 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018770 alc663_two_hp_amic_m1_init_verbs },
18771 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18772 .hp_nid = 0x03,
18773 .dac_nids = alc662_dac_nids,
18774 .dig_out_nid = ALC662_DIGOUT_NID,
18775 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18776 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018777 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018778 .setup = alc663_mode3_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018779 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018780 },
18781 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018782 .mixers = { alc663_asus_21jd_clfe_mixer },
18783 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018784 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018785 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018786 alc663_21jd_amic_init_verbs},
18787 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18788 .hp_nid = 0x03,
18789 .dac_nids = alc662_dac_nids,
18790 .dig_out_nid = ALC662_DIGOUT_NID,
18791 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18792 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018793 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018794 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018795 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018796 },
18797 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018798 .mixers = { alc663_asus_15jd_clfe_mixer },
18799 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018800 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018801 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018802 alc663_15jd_amic_init_verbs },
18803 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18804 .hp_nid = 0x03,
18805 .dac_nids = alc662_dac_nids,
18806 .dig_out_nid = ALC662_DIGOUT_NID,
18807 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18808 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018809 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018810 .setup = alc663_mode5_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018811 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018812 },
18813 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018814 .mixers = { alc663_two_hp_m2_mixer },
18815 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018816 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018817 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018818 alc663_two_hp_amic_m2_init_verbs },
18819 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18820 .hp_nid = 0x03,
18821 .dac_nids = alc662_dac_nids,
18822 .dig_out_nid = ALC662_DIGOUT_NID,
18823 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18824 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018825 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018826 .setup = alc663_mode6_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018827 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018828 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018829 [ALC663_ASUS_MODE7] = {
18830 .mixers = { alc663_mode7_mixer },
18831 .cap_mixer = alc662_auto_capture_mixer,
18832 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018833 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018834 alc663_mode7_init_verbs },
18835 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18836 .hp_nid = 0x03,
18837 .dac_nids = alc662_dac_nids,
18838 .dig_out_nid = ALC662_DIGOUT_NID,
18839 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18840 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018841 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018842 .setup = alc663_mode7_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018843 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018844 },
18845 [ALC663_ASUS_MODE8] = {
18846 .mixers = { alc663_mode8_mixer },
18847 .cap_mixer = alc662_auto_capture_mixer,
18848 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018849 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018850 alc663_mode8_init_verbs },
18851 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18852 .hp_nid = 0x03,
18853 .dac_nids = alc662_dac_nids,
18854 .dig_out_nid = ALC662_DIGOUT_NID,
18855 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18856 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018857 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018858 .setup = alc663_mode8_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018859 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018860 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018861 [ALC272_DELL] = {
18862 .mixers = { alc663_m51va_mixer },
18863 .cap_mixer = alc272_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018864 .init_verbs = { alc662_init_verbs,
18865 alc662_eapd_init_verbs,
18866 alc272_dell_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018867 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018868 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018869 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18870 .adc_nids = alc272_adc_nids,
18871 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18872 .capsrc_nids = alc272_capsrc_nids,
18873 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018874 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018875 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018876 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018877 },
18878 [ALC272_DELL_ZM1] = {
18879 .mixers = { alc663_m51va_mixer },
18880 .cap_mixer = alc662_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018881 .init_verbs = { alc662_init_verbs,
18882 alc662_eapd_init_verbs,
18883 alc272_dell_zm1_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018884 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018885 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018886 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18887 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018888 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018889 .capsrc_nids = alc662_capsrc_nids,
18890 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018891 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018892 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018893 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018894 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018895 [ALC272_SAMSUNG_NC10] = {
18896 .mixers = { alc272_nc10_mixer },
18897 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018898 alc662_eapd_init_verbs,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018899 alc663_21jd_amic_init_verbs },
18900 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18901 .dac_nids = alc272_dac_nids,
18902 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18903 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018904 /*.input_mux = &alc272_nc10_capture_source,*/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018905 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018906 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018907 .init_hook = alc_inithook,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018908 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018909};
18910
18911
18912/*
18913 * BIOS auto configuration
18914 */
18915
Takashi Iwai7085ec12009-10-02 09:03:58 +020018916/* convert from MIX nid to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018917static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018918{
Takashi Iwai604401a2011-04-27 15:14:23 +020018919 hda_nid_t list[5];
Takashi Iwai1304ac82011-04-06 15:16:21 +020018920 int i, num;
18921
18922 num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
18923 for (i = 0; i < num; i++) {
18924 if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
18925 return list[i];
18926 }
18927 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018928}
18929
Takashi Iwai604401a2011-04-27 15:14:23 +020018930/* go down to the selector widget before the mixer */
18931static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
18932{
18933 hda_nid_t srcs[5];
18934 int num = snd_hda_get_connections(codec, pin, srcs,
18935 ARRAY_SIZE(srcs));
18936 if (num != 1 ||
18937 get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
18938 return pin;
18939 return srcs[0];
18940}
18941
Takashi Iwai7085ec12009-10-02 09:03:58 +020018942/* get MIX nid connected to the given pin targeted to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018943static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018944 hda_nid_t dac)
18945{
David Henningssoncc1c4522010-11-24 14:17:47 +010018946 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018947 int i, num;
18948
Takashi Iwai604401a2011-04-27 15:14:23 +020018949 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018950 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18951 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018952 if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018953 return mix[i];
18954 }
18955 return 0;
18956}
18957
Takashi Iwaice764ab2011-04-27 16:35:23 +020018958/* select the connection from pin to DAC if needed */
18959static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
18960 hda_nid_t dac)
18961{
18962 hda_nid_t mix[5];
18963 int i, num;
18964
18965 pin = alc_go_down_to_selector(codec, pin);
18966 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18967 if (num < 2)
18968 return 0;
18969 for (i = 0; i < num; i++) {
18970 if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
18971 snd_hda_codec_update_cache(codec, pin, 0,
18972 AC_VERB_SET_CONNECT_SEL, i);
18973 return 0;
18974 }
18975 }
18976 return 0;
18977}
18978
Takashi Iwai7085ec12009-10-02 09:03:58 +020018979/* look for an empty DAC slot */
Takashi Iwai604401a2011-04-27 15:14:23 +020018980static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018981{
18982 struct alc_spec *spec = codec->spec;
18983 hda_nid_t srcs[5];
18984 int i, j, num;
18985
Takashi Iwai604401a2011-04-27 15:14:23 +020018986 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018987 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018988 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018989 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018990 if (!nid)
18991 continue;
18992 for (j = 0; j < spec->multiout.num_dacs; j++)
18993 if (spec->multiout.dac_nids[j] == nid)
18994 break;
18995 if (j >= spec->multiout.num_dacs)
18996 return nid;
18997 }
18998 return 0;
18999}
19000
19001/* fill in the dac_nids table from the parsed pin configuration */
19002static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
19003 const struct auto_pin_cfg *cfg)
19004{
19005 struct alc_spec *spec = codec->spec;
19006 int i;
19007 hda_nid_t dac;
19008
19009 spec->multiout.dac_nids = spec->private_dac_nids;
19010 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020019011 dac = alc_auto_look_for_dac(codec, cfg->line_out_pins[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019012 if (!dac)
19013 continue;
Takashi Iwaidda14412011-05-02 11:29:30 +020019014 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019015 }
19016 return 0;
19017}
19018
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019019static inline int __alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
19020 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019021{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019022 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019023 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
19024}
19025
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019026static inline int __alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
19027 hda_nid_t nid, int idx, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019028{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019029 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019030 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
19031}
19032
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019033#define alc662_add_vol_ctl(spec, pfx, nid, chs) \
19034 __alc662_add_vol_ctl(spec, pfx, nid, 0, chs)
19035#define alc662_add_sw_ctl(spec, pfx, nid, chs) \
19036 __alc662_add_sw_ctl(spec, pfx, nid, 0, chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019037#define alc662_add_stereo_vol(spec, pfx, nid) \
19038 alc662_add_vol_ctl(spec, pfx, nid, 3)
19039#define alc662_add_stereo_sw(spec, pfx, nid) \
19040 alc662_add_sw_ctl(spec, pfx, nid, 3)
19041
19042/* add playback controls from the parsed DAC table */
19043static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
19044 const struct auto_pin_cfg *cfg)
19045{
19046 struct alc_spec *spec = codec->spec;
Takashi Iwaiea734962011-01-17 11:29:34 +010019047 static const char * const chname[4] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019048 "Front", "Surround", NULL /*CLFE*/, "Side"
19049 };
Takashi Iwaice764ab2011-04-27 16:35:23 +020019050 const char *pfx = alc_get_line_out_pfx(spec, true);
19051 hda_nid_t nid, mix, pin;
19052 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019053
Takashi Iwaice764ab2011-04-27 16:35:23 +020019054 noutputs = cfg->line_outs;
19055 if (spec->multi_ios > 0)
19056 noutputs += spec->multi_ios;
19057
19058 for (i = 0; i < noutputs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019059 nid = spec->multiout.dac_nids[i];
19060 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019061 continue;
Takashi Iwaice764ab2011-04-27 16:35:23 +020019062 if (i >= cfg->line_outs)
19063 pin = spec->multi_io[i - 1].pin;
19064 else
19065 pin = cfg->line_out_pins[i];
19066 mix = alc_auto_dac_to_mix(codec, pin, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019067 if (!mix)
19068 continue;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019069 if (!pfx && i == 2) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019070 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019071 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019072 if (err < 0)
19073 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019074 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019075 if (err < 0)
19076 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019077 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019078 if (err < 0)
19079 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019080 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019081 if (err < 0)
19082 return err;
19083 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019084 const char *name = pfx;
David Henningsson5a882642011-03-23 08:35:07 +010019085 int index = i;
19086 if (!name) {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010019087 name = chname[i];
David Henningsson5a882642011-03-23 08:35:07 +010019088 index = 0;
19089 }
19090 err = __alc662_add_vol_ctl(spec, name, nid, index, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019091 if (err < 0)
19092 return err;
David Henningsson5a882642011-03-23 08:35:07 +010019093 err = __alc662_add_sw_ctl(spec, name, mix, index, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019094 if (err < 0)
19095 return err;
19096 }
19097 }
19098 return 0;
19099}
19100
19101/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019102/* return DAC nid if any new DAC is assigned */
19103static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019104 const char *pfx)
19105{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019106 struct alc_spec *spec = codec->spec;
19107 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019108 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019109
19110 if (!pin)
19111 return 0;
Takashi Iwai604401a2011-04-27 15:14:23 +020019112 nid = alc_auto_look_for_dac(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019113 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019114 /* the corresponding DAC is already occupied */
19115 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
19116 return 0; /* no way */
19117 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019118 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019119 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
19120 }
19121
Takashi Iwai604401a2011-04-27 15:14:23 +020019122 mix = alc_auto_dac_to_mix(codec, pin, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019123 if (!mix)
19124 return 0;
19125 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
19126 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020019127 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019128 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
19129 if (err < 0)
19130 return err;
19131 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019132}
19133
19134/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020019135#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020019136 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019137
19138static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
19139 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019140 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019141{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019142 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020019143 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019144
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019145 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai7085ec12009-10-02 09:03:58 +020019146 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020019147 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020019148 if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019149 continue;
Takashi Iwai0e53f342011-04-07 12:27:32 +020019150 /* need the manual connection? */
19151 if (num > 1)
19152 snd_hda_codec_write(codec, nid, 0,
19153 AC_VERB_SET_CONNECT_SEL, i);
19154 /* unmute mixer widget inputs */
19155 snd_hda_codec_write(codec, srcs[i], 0,
19156 AC_VERB_SET_AMP_GAIN_MUTE,
19157 AMP_IN_UNMUTE(0));
19158 snd_hda_codec_write(codec, srcs[i], 0,
19159 AC_VERB_SET_AMP_GAIN_MUTE,
19160 AMP_IN_UNMUTE(1));
Takashi Iwai7085ec12009-10-02 09:03:58 +020019161 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019162 }
19163}
19164
19165static void alc662_auto_init_multi_out(struct hda_codec *codec)
19166{
19167 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019168 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019169 int i;
19170
19171 for (i = 0; i <= HDA_SIDE; i++) {
19172 hda_nid_t nid = spec->autocfg.line_out_pins[i];
19173 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020019174 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019175 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019176 }
19177}
19178
19179static void alc662_auto_init_hp_out(struct hda_codec *codec)
19180{
19181 struct alc_spec *spec = codec->spec;
19182 hda_nid_t pin;
19183
19184 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019185 if (pin)
19186 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
19187 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019188 pin = spec->autocfg.speaker_pins[0];
19189 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019190 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
19191 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019192}
19193
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019194#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
19195
19196static void alc662_auto_init_analog_input(struct hda_codec *codec)
19197{
19198 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019199 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019200 int i;
19201
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019202 for (i = 0; i < cfg->num_inputs; i++) {
19203 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019204 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020019205 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010019206 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010019207 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019208 snd_hda_codec_write(codec, nid, 0,
19209 AC_VERB_SET_AMP_GAIN_MUTE,
19210 AMP_OUT_MUTE);
19211 }
19212 }
19213}
19214
Takashi Iwaif511b012008-08-15 16:46:42 +020019215#define alc662_auto_init_input_src alc882_auto_init_input_src
19216
Takashi Iwaice764ab2011-04-27 16:35:23 +020019217/*
19218 * multi-io helper
19219 */
19220static int alc_auto_fill_multi_ios(struct hda_codec *codec,
19221 unsigned int location)
19222{
19223 struct alc_spec *spec = codec->spec;
19224 struct auto_pin_cfg *cfg = &spec->autocfg;
19225 int type, i, num_pins = 0;
19226
19227 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
19228 for (i = 0; i < cfg->num_inputs; i++) {
19229 hda_nid_t nid = cfg->inputs[i].pin;
19230 hda_nid_t dac;
19231 unsigned int defcfg, caps;
19232 if (cfg->inputs[i].type != type)
19233 continue;
19234 defcfg = snd_hda_codec_get_pincfg(codec, nid);
19235 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
19236 continue;
19237 if (location && get_defcfg_location(defcfg) != location)
19238 continue;
19239 caps = snd_hda_query_pin_caps(codec, nid);
19240 if (!(caps & AC_PINCAP_OUT))
19241 continue;
19242 dac = alc_auto_look_for_dac(codec, nid);
19243 if (!dac)
19244 continue;
19245 spec->multi_io[num_pins].pin = nid;
19246 spec->multi_io[num_pins].dac = dac;
19247 num_pins++;
Takashi Iwaidda14412011-05-02 11:29:30 +020019248 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +020019249 }
19250 }
19251 spec->multiout.num_dacs = 1;
19252 if (num_pins < 2)
19253 return 0;
19254 return num_pins;
19255}
19256
19257static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
19258 struct snd_ctl_elem_info *uinfo)
19259{
19260 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
19261 struct alc_spec *spec = codec->spec;
19262
19263 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
19264 uinfo->count = 1;
19265 uinfo->value.enumerated.items = spec->multi_ios + 1;
19266 if (uinfo->value.enumerated.item > spec->multi_ios)
19267 uinfo->value.enumerated.item = spec->multi_ios;
19268 sprintf(uinfo->value.enumerated.name, "%dch",
19269 (uinfo->value.enumerated.item + 1) * 2);
19270 return 0;
19271}
19272
19273static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
19274 struct snd_ctl_elem_value *ucontrol)
19275{
19276 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
19277 struct alc_spec *spec = codec->spec;
19278 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
19279 return 0;
19280}
19281
19282static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
19283{
19284 struct alc_spec *spec = codec->spec;
19285 hda_nid_t nid = spec->multi_io[idx].pin;
19286
19287 if (!spec->multi_io[idx].ctl_in)
19288 spec->multi_io[idx].ctl_in =
19289 snd_hda_codec_read(codec, nid, 0,
19290 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
19291 if (output) {
19292 snd_hda_codec_update_cache(codec, nid, 0,
19293 AC_VERB_SET_PIN_WIDGET_CONTROL,
19294 PIN_OUT);
19295 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
19296 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
19297 HDA_AMP_MUTE, 0);
19298 alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
19299 } else {
19300 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
19301 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
19302 HDA_AMP_MUTE, HDA_AMP_MUTE);
19303 snd_hda_codec_update_cache(codec, nid, 0,
19304 AC_VERB_SET_PIN_WIDGET_CONTROL,
19305 spec->multi_io[idx].ctl_in);
19306 }
19307 return 0;
19308}
19309
19310static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
19311 struct snd_ctl_elem_value *ucontrol)
19312{
19313 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
19314 struct alc_spec *spec = codec->spec;
19315 int i, ch;
19316
19317 ch = ucontrol->value.enumerated.item[0];
19318 if (ch < 0 || ch > spec->multi_ios)
19319 return -EINVAL;
19320 if (ch == (spec->ext_channel_count - 1) / 2)
19321 return 0;
19322 spec->ext_channel_count = (ch + 1) * 2;
19323 for (i = 0; i < spec->multi_ios; i++)
19324 alc_set_multi_io(codec, i, i < ch);
19325 spec->multiout.max_channels = spec->ext_channel_count;
19326 return 1;
19327}
19328
Takashi Iwaia9111322011-05-02 11:30:18 +020019329static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +020019330 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
19331 .name = "Channel Mode",
19332 .info = alc_auto_ch_mode_info,
19333 .get = alc_auto_ch_mode_get,
19334 .put = alc_auto_ch_mode_put,
19335};
19336
19337static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
19338{
19339 struct alc_spec *spec = codec->spec;
19340 struct auto_pin_cfg *cfg = &spec->autocfg;
19341 unsigned int location, defcfg;
19342 int num_pins;
19343
19344 if (cfg->line_outs != 1 ||
19345 cfg->line_out_type != AUTO_PIN_LINE_OUT)
19346 return 0;
19347
19348 defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
19349 location = get_defcfg_location(defcfg);
19350
19351 num_pins = alc_auto_fill_multi_ios(codec, location);
19352 if (num_pins > 0) {
19353 struct snd_kcontrol_new *knew;
19354
19355 knew = alc_kcontrol_new(spec);
19356 if (!knew)
19357 return -ENOMEM;
19358 *knew = alc_auto_channel_mode_enum;
19359 knew->name = kstrdup("Channel Mode", GFP_KERNEL);
19360 if (!knew->name)
19361 return -ENOMEM;
19362
19363 spec->multi_ios = num_pins;
19364 spec->ext_channel_count = 2;
19365 spec->multiout.num_dacs = num_pins + 1;
19366 }
19367 return 0;
19368}
19369
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019370static int alc662_parse_auto_config(struct hda_codec *codec)
19371{
19372 struct alc_spec *spec = codec->spec;
19373 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019374 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019375
19376 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19377 alc662_ignore);
19378 if (err < 0)
19379 return err;
19380 if (!spec->autocfg.line_outs)
19381 return 0; /* can't find valid BIOS pin config */
19382
Takashi Iwai7085ec12009-10-02 09:03:58 +020019383 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019384 if (err < 0)
19385 return err;
Takashi Iwaice764ab2011-04-27 16:35:23 +020019386 err = alc_auto_add_multi_channel_mode(codec);
19387 if (err < 0)
19388 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019389 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019390 if (err < 0)
19391 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019392 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019393 spec->autocfg.speaker_pins[0],
19394 "Speaker");
19395 if (err < 0)
19396 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019397 if (err)
19398 spec->multiout.extra_out_nid[0] = err;
19399 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019400 "Headphone");
19401 if (err < 0)
19402 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019403 if (err)
19404 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019405 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019406 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019407 return err;
19408
19409 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
19410
Takashi Iwai757899a2010-07-30 10:48:14 +020019411 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019412
Takashi Iwai603c4012008-07-30 15:01:44 +020019413 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010019414 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019415
19416 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020019417 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020019418
Takashi Iwaiee979a142008-09-02 15:42:20 +020019419 err = alc_auto_add_mic_boost(codec);
19420 if (err < 0)
19421 return err;
19422
Kailang Yang6227cdc2010-02-25 08:36:52 +010019423 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
19424 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
19425 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
19426 else
19427 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020019428
Takashi Iwai8c872862007-06-19 12:11:16 +020019429 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019430}
19431
19432/* additional initialization for auto-configuration model */
19433static void alc662_auto_init(struct hda_codec *codec)
19434{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019435 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019436 alc662_auto_init_multi_out(codec);
19437 alc662_auto_init_hp_out(codec);
19438 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019439 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019440 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019441 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019442 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019443}
19444
Todd Broch6be79482010-12-07 16:51:05 -080019445static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019446 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019447{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019448 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010019449 return;
Todd Broch6be79482010-12-07 16:51:05 -080019450 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
19451 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
19452 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
19453 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
19454 (0 << AC_AMPCAP_MUTE_SHIFT)))
19455 printk(KERN_WARNING
19456 "hda_codec: failed to override amp caps for NID 0x2\n");
19457}
19458
David Henningsson6cb3b702010-09-09 08:51:44 +020019459enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040019460 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019461 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080019462 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019463 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +020019464 ALC662_FIXUP_SKU_IGNORE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019465};
19466
19467static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019468 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019469 .type = ALC_FIXUP_PINS,
19470 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -040019471 { 0x15, 0x99130112 }, /* subwoofer */
19472 { }
19473 }
19474 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019475 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019476 .type = ALC_FIXUP_PINS,
19477 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019478 { 0x17, 0x99130112 }, /* subwoofer */
19479 { }
19480 }
19481 },
Todd Broch6be79482010-12-07 16:51:05 -080019482 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019483 .type = ALC_FIXUP_FUNC,
19484 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +010019485 },
19486 [ALC662_FIXUP_CZC_P10T] = {
19487 .type = ALC_FIXUP_VERBS,
19488 .v.verbs = (const struct hda_verb[]) {
19489 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
19490 {}
19491 }
19492 },
David Henningsson94024cd2011-04-29 14:10:55 +020019493 [ALC662_FIXUP_SKU_IGNORE] = {
19494 .type = ALC_FIXUP_SKU,
19495 .v.sku = ALC_FIXUP_SKU_IGNORE,
Takashi Iwaic6b35872011-03-28 12:05:31 +020019496 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019497};
19498
Takashi Iwaia9111322011-05-02 11:30:18 +020019499static const struct snd_pci_quirk alc662_fixup_tbl[] = {
David Henningssona6c47a82011-02-10 15:39:19 +010019500 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +020019501 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Daniel T Chen2df03512010-10-10 22:39:28 -040019502 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050019503 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060019504 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020019505 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +010019506 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
David Henningsson6cb3b702010-09-09 08:51:44 +020019507 {}
19508};
19509
Todd Broch6be79482010-12-07 16:51:05 -080019510static const struct alc_model_fixup alc662_fixup_models[] = {
19511 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
19512 {}
19513};
David Henningsson6cb3b702010-09-09 08:51:44 +020019514
19515
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019516static int patch_alc662(struct hda_codec *codec)
19517{
19518 struct alc_spec *spec;
19519 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020019520 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019521
19522 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19523 if (!spec)
19524 return -ENOMEM;
19525
19526 codec->spec = spec;
19527
Kailang Yangda00c242010-03-19 11:23:45 +010019528 alc_auto_parse_customize_define(codec);
19529
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019530 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19531
Kailang Yang693194f2010-10-21 08:51:48 +020019532 coef = alc_read_coef_idx(codec, 0);
19533 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019534 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020019535 else if (coef & (1 << 14) &&
19536 codec->bus->pci->subsystem_vendor == 0x1025 &&
19537 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019538 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020019539 else if (coef == 0x4011)
19540 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010019541
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019542 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19543 alc662_models,
19544 alc662_cfg_tbl);
19545 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019546 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19547 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019548 board_config = ALC662_AUTO;
19549 }
19550
19551 if (board_config == ALC662_AUTO) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019552 alc_pick_fixup(codec, alc662_fixup_models,
19553 alc662_fixup_tbl, alc662_fixups);
19554 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019555 /* automatic parse from the BIOS config */
19556 err = alc662_parse_auto_config(codec);
19557 if (err < 0) {
19558 alc_free(codec);
19559 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020019560 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019561 printk(KERN_INFO
19562 "hda_codec: Cannot set up configuration "
19563 "from BIOS. Using base mode...\n");
19564 board_config = ALC662_3ST_2ch_DIG;
19565 }
19566 }
19567
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019568 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019569 err = snd_hda_attach_beep_device(codec, 0x1);
19570 if (err < 0) {
19571 alc_free(codec);
19572 return err;
19573 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019574 }
19575
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019576 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019577 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019578
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019579 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19580 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19581
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019582 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19583 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19584
Takashi Iwaidd704692009-08-11 08:45:11 +020019585 if (!spec->adc_nids) {
19586 spec->adc_nids = alc662_adc_nids;
19587 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19588 }
19589 if (!spec->capsrc_nids)
19590 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019591
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019592 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019593 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019594
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019595 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019596 switch (codec->vendor_id) {
19597 case 0x10ec0662:
19598 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19599 break;
19600 case 0x10ec0272:
19601 case 0x10ec0663:
19602 case 0x10ec0665:
19603 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19604 break;
19605 case 0x10ec0273:
19606 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19607 break;
19608 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019609 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019610 spec->vmaster_nid = 0x02;
19611
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019612 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
19613
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019614 codec->patch_ops = alc_patch_ops;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010019615 if (board_config == ALC662_AUTO)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019616 spec->init_hook = alc662_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020019617 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +020019618
Kailang Yangbf1b0222010-10-21 08:49:56 +020019619 alc_init_jacks(codec);
19620
Takashi Iwaicb53c622007-08-10 17:21:45 +020019621#ifdef CONFIG_SND_HDA_POWER_SAVE
19622 if (!spec->loopback.amplist)
19623 spec->loopback.amplist = alc662_loopbacks;
19624#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019625
19626 return 0;
19627}
19628
Kailang Yang274693f2009-12-03 10:07:50 +010019629static int patch_alc888(struct hda_codec *codec)
19630{
19631 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19632 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010019633 if (codec->vendor_id == 0x10ec0887)
19634 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
19635 else
19636 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019637 if (!codec->chip_name) {
19638 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019639 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019640 }
19641 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019642 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019643 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019644}
19645
Kailang Yangb478b992011-05-18 11:51:15 +020019646static int patch_alc899(struct hda_codec *codec)
19647{
19648 if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
19649 kfree(codec->chip_name);
19650 codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
19651 }
19652 return patch_alc882(codec);
19653}
19654
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019655/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019656 * ALC680 support
19657 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019658#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019659#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19660#define alc680_modes alc260_modes
19661
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019662static const hda_nid_t alc680_dac_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019663 /* Lout1, Lout2, hp */
19664 0x02, 0x03, 0x04
19665};
19666
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019667static const hda_nid_t alc680_adc_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019668 /* ADC0-2 */
19669 /* DMIC, MIC, Line-in*/
19670 0x07, 0x08, 0x09
19671};
19672
Kailang Yangc69aefa2010-08-17 10:39:22 +020019673/*
19674 * Analog capture ADC cgange
19675 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019676static void alc680_rec_autoswitch(struct hda_codec *codec)
19677{
19678 struct alc_spec *spec = codec->spec;
19679 struct auto_pin_cfg *cfg = &spec->autocfg;
19680 int pin_found = 0;
19681 int type_found = AUTO_PIN_LAST;
19682 hda_nid_t nid;
19683 int i;
19684
19685 for (i = 0; i < cfg->num_inputs; i++) {
19686 nid = cfg->inputs[i].pin;
Takashi Iwai06dec222011-05-17 10:00:16 +020019687 if (!is_jack_detectable(codec, nid))
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019688 continue;
19689 if (snd_hda_jack_detect(codec, nid)) {
19690 if (cfg->inputs[i].type < type_found) {
19691 type_found = cfg->inputs[i].type;
19692 pin_found = nid;
19693 }
19694 }
19695 }
19696
19697 nid = 0x07;
19698 if (pin_found)
19699 snd_hda_get_connections(codec, pin_found, &nid, 1);
19700
19701 if (nid != spec->cur_adc)
19702 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19703 spec->cur_adc = nid;
19704 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19705 spec->cur_adc_format);
19706}
19707
Kailang Yangc69aefa2010-08-17 10:39:22 +020019708static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19709 struct hda_codec *codec,
19710 unsigned int stream_tag,
19711 unsigned int format,
19712 struct snd_pcm_substream *substream)
19713{
19714 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019715
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019716 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019717 spec->cur_adc_stream_tag = stream_tag;
19718 spec->cur_adc_format = format;
19719
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019720 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019721 return 0;
19722}
19723
19724static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19725 struct hda_codec *codec,
19726 struct snd_pcm_substream *substream)
19727{
19728 snd_hda_codec_cleanup_stream(codec, 0x07);
19729 snd_hda_codec_cleanup_stream(codec, 0x08);
19730 snd_hda_codec_cleanup_stream(codec, 0x09);
19731 return 0;
19732}
19733
Takashi Iwaia9111322011-05-02 11:30:18 +020019734static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019735 .substreams = 1, /* can be overridden */
19736 .channels_min = 2,
19737 .channels_max = 2,
19738 /* NID is set in alc_build_pcms */
19739 .ops = {
19740 .prepare = alc680_capture_pcm_prepare,
19741 .cleanup = alc680_capture_pcm_cleanup
19742 },
19743};
19744
Takashi Iwaia9111322011-05-02 11:30:18 +020019745static const struct snd_kcontrol_new alc680_base_mixer[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019746 /* output mixer control */
19747 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19748 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19749 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19750 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019751 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19752 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19753 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019754 { }
19755};
19756
Takashi Iwaia9111322011-05-02 11:30:18 +020019757static const struct hda_bind_ctls alc680_bind_cap_vol = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019758 .ops = &snd_hda_bind_vol,
19759 .values = {
19760 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19761 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19762 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19763 0
19764 },
19765};
19766
Takashi Iwaia9111322011-05-02 11:30:18 +020019767static const struct hda_bind_ctls alc680_bind_cap_switch = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019768 .ops = &snd_hda_bind_sw,
19769 .values = {
19770 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19771 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19772 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19773 0
19774 },
19775};
19776
Takashi Iwaia9111322011-05-02 11:30:18 +020019777static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019778 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19779 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019780 { } /* end */
19781};
19782
19783/*
19784 * generic initialization of ADC, input mixers and output mixers
19785 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019786static const struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019787 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19788 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19789 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019790
Kailang Yangc69aefa2010-08-17 10:39:22 +020019791 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19792 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19793 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19794 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19795 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19796 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019797
19798 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19799 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19800 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19801 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19802 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019803
19804 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19805 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019806 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019807
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019808 { }
19809};
19810
Kailang Yangc69aefa2010-08-17 10:39:22 +020019811/* toggle speaker-output according to the hp-jack state */
19812static void alc680_base_setup(struct hda_codec *codec)
19813{
19814 struct alc_spec *spec = codec->spec;
19815
19816 spec->autocfg.hp_pins[0] = 0x16;
19817 spec->autocfg.speaker_pins[0] = 0x14;
19818 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019819 spec->autocfg.num_inputs = 2;
19820 spec->autocfg.inputs[0].pin = 0x18;
19821 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19822 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019823 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Takashi Iwaid922b512011-04-28 12:18:53 +020019824 spec->automute = 1;
19825 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019826}
19827
19828static void alc680_unsol_event(struct hda_codec *codec,
19829 unsigned int res)
19830{
19831 if ((res >> 26) == ALC880_HP_EVENT)
Takashi Iwaid922b512011-04-28 12:18:53 +020019832 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019833 if ((res >> 26) == ALC880_MIC_EVENT)
19834 alc680_rec_autoswitch(codec);
19835}
19836
19837static void alc680_inithook(struct hda_codec *codec)
19838{
Takashi Iwaid922b512011-04-28 12:18:53 +020019839 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019840 alc680_rec_autoswitch(codec);
19841}
19842
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019843/* create input playback/capture controls for the given pin */
19844static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19845 const char *ctlname, int idx)
19846{
19847 hda_nid_t dac;
19848 int err;
19849
19850 switch (nid) {
19851 case 0x14:
19852 dac = 0x02;
19853 break;
19854 case 0x15:
19855 dac = 0x03;
19856 break;
19857 case 0x16:
19858 dac = 0x04;
19859 break;
19860 default:
19861 return 0;
19862 }
19863 if (spec->multiout.dac_nids[0] != dac &&
19864 spec->multiout.dac_nids[1] != dac) {
19865 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19866 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19867 HDA_OUTPUT));
19868 if (err < 0)
19869 return err;
19870
19871 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19872 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19873
19874 if (err < 0)
19875 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020019876 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019877 }
19878
19879 return 0;
19880}
19881
19882/* add playback controls from the parsed DAC table */
19883static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19884 const struct auto_pin_cfg *cfg)
19885{
19886 hda_nid_t nid;
19887 int err;
19888
19889 spec->multiout.dac_nids = spec->private_dac_nids;
19890
19891 nid = cfg->line_out_pins[0];
19892 if (nid) {
19893 const char *name;
19894 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19895 name = "Speaker";
19896 else
19897 name = "Front";
19898 err = alc680_new_analog_output(spec, nid, name, 0);
19899 if (err < 0)
19900 return err;
19901 }
19902
19903 nid = cfg->speaker_pins[0];
19904 if (nid) {
19905 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19906 if (err < 0)
19907 return err;
19908 }
19909 nid = cfg->hp_pins[0];
19910 if (nid) {
19911 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19912 if (err < 0)
19913 return err;
19914 }
19915
19916 return 0;
19917}
19918
19919static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19920 hda_nid_t nid, int pin_type)
19921{
19922 alc_set_pin_output(codec, nid, pin_type);
19923}
19924
19925static void alc680_auto_init_multi_out(struct hda_codec *codec)
19926{
19927 struct alc_spec *spec = codec->spec;
19928 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19929 if (nid) {
19930 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19931 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19932 }
19933}
19934
19935static void alc680_auto_init_hp_out(struct hda_codec *codec)
19936{
19937 struct alc_spec *spec = codec->spec;
19938 hda_nid_t pin;
19939
19940 pin = spec->autocfg.hp_pins[0];
19941 if (pin)
19942 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19943 pin = spec->autocfg.speaker_pins[0];
19944 if (pin)
19945 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19946}
19947
19948/* pcm configuration: identical with ALC880 */
19949#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19950#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19951#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19952#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019953#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019954
19955/*
19956 * BIOS auto configuration
19957 */
19958static int alc680_parse_auto_config(struct hda_codec *codec)
19959{
19960 struct alc_spec *spec = codec->spec;
19961 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019962 static const hda_nid_t alc680_ignore[] = { 0 };
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019963
19964 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19965 alc680_ignore);
19966 if (err < 0)
19967 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019968
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019969 if (!spec->autocfg.line_outs) {
19970 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19971 spec->multiout.max_channels = 2;
19972 spec->no_analog = 1;
19973 goto dig_only;
19974 }
19975 return 0; /* can't find valid BIOS pin config */
19976 }
19977 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19978 if (err < 0)
19979 return err;
19980
19981 spec->multiout.max_channels = 2;
19982
19983 dig_only:
19984 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019985 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019986 if (spec->kctls.list)
19987 add_mixer(spec, spec->kctls.list);
19988
19989 add_verb(spec, alc680_init_verbs);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019990
19991 err = alc_auto_add_mic_boost(codec);
19992 if (err < 0)
19993 return err;
19994
19995 return 1;
19996}
19997
19998#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19999
20000/* init callback for auto-configuration model -- overriding the default init */
20001static void alc680_auto_init(struct hda_codec *codec)
20002{
20003 struct alc_spec *spec = codec->spec;
20004 alc680_auto_init_multi_out(codec);
20005 alc680_auto_init_hp_out(codec);
20006 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020020007 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020008 if (spec->unsol_event)
20009 alc_inithook(codec);
20010}
20011
20012/*
20013 * configuration and preset
20014 */
Takashi Iwaiea734962011-01-17 11:29:34 +010020015static const char * const alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020020016 [ALC680_BASE] = "base",
20017 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020018};
20019
Takashi Iwaia9111322011-05-02 11:30:18 +020020020static const struct snd_pci_quirk alc680_cfg_tbl[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020021 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
20022 {}
20023};
20024
Takashi Iwaia9111322011-05-02 11:30:18 +020020025static const struct alc_config_preset alc680_presets[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020026 [ALC680_BASE] = {
20027 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020020028 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020029 .init_verbs = { alc680_init_verbs },
20030 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
20031 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020032 .dig_out_nid = ALC680_DIGOUT_NID,
20033 .num_channel_mode = ARRAY_SIZE(alc680_modes),
20034 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020020035 .unsol_event = alc680_unsol_event,
20036 .setup = alc680_base_setup,
20037 .init_hook = alc680_inithook,
20038
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020039 },
20040};
20041
20042static int patch_alc680(struct hda_codec *codec)
20043{
20044 struct alc_spec *spec;
20045 int board_config;
20046 int err;
20047
20048 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
20049 if (spec == NULL)
20050 return -ENOMEM;
20051
20052 codec->spec = spec;
20053
20054 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
20055 alc680_models,
20056 alc680_cfg_tbl);
20057
20058 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
20059 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
20060 codec->chip_name);
20061 board_config = ALC680_AUTO;
20062 }
20063
20064 if (board_config == ALC680_AUTO) {
20065 /* automatic parse from the BIOS config */
20066 err = alc680_parse_auto_config(codec);
20067 if (err < 0) {
20068 alc_free(codec);
20069 return err;
20070 } else if (!err) {
20071 printk(KERN_INFO
20072 "hda_codec: Cannot set up configuration "
20073 "from BIOS. Using base mode...\n");
20074 board_config = ALC680_BASE;
20075 }
20076 }
20077
20078 if (board_config != ALC680_AUTO)
20079 setup_preset(codec, &alc680_presets[board_config]);
20080
20081 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020082 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020083 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020020084 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020085
20086 if (!spec->adc_nids) {
20087 spec->adc_nids = alc680_adc_nids;
20088 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
20089 }
20090
20091 if (!spec->cap_mixer)
20092 set_capture_mixer(codec);
20093
20094 spec->vmaster_nid = 0x02;
20095
20096 codec->patch_ops = alc_patch_ops;
20097 if (board_config == ALC680_AUTO)
20098 spec->init_hook = alc680_auto_init;
20099
20100 return 0;
20101}
20102
20103/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070020104 * patch entries
20105 */
Takashi Iwaia9111322011-05-02 11:30:18 +020020106static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +020020107 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020108 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020109 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020110 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020020111 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010020112 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020113 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020020114 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010020115 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +020020116 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020117 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020118 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020119 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
20120 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
20121 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020122 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020020123 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020020124 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
20125 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020020126 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010020127 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010020128 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020020129 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010020130 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020131 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020020132 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020020133 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020020134 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020020135 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020020136 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020137 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010020138 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020020139 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020020140 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020141 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020020142 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020143 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Kailang Yangb478b992011-05-18 11:51:15 +020020144 { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020145 {} /* terminator */
20146};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010020147
20148MODULE_ALIAS("snd-hda-codec-id:10ec*");
20149
20150MODULE_LICENSE("GPL");
20151MODULE_DESCRIPTION("Realtek HD-audio codec");
20152
20153static struct hda_codec_preset_list realtek_list = {
20154 .preset = snd_hda_preset_realtek,
20155 .owner = THIS_MODULE,
20156};
20157
20158static int __init patch_realtek_init(void)
20159{
20160 return snd_hda_add_codec_preset(&realtek_list);
20161}
20162
20163static void __exit patch_realtek_exit(void)
20164{
20165 snd_hda_delete_codec_preset(&realtek_list);
20166}
20167
20168module_init(patch_realtek_init)
20169module_exit(patch_realtek_exit)