blob: 42026f4978c3a490f8743f8242ece182ed54c1e3 [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
Kailang Yangda00c242010-03-19 11:23:45 +0100279struct alc_customize_define {
280 unsigned int sku_cfg;
281 unsigned char port_connectivity;
282 unsigned char check_sum;
283 unsigned char customization;
284 unsigned char external_amp;
285 unsigned int enable_pcbeep:1;
286 unsigned int platform_type:1;
287 unsigned int swap:1;
288 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +0200289 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +0100290};
291
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100292struct alc_fixup;
293
Takashi Iwaice764ab2011-04-27 16:35:23 +0200294struct alc_multi_io {
295 hda_nid_t pin; /* multi-io widget pin NID */
296 hda_nid_t dac; /* DAC to be connected */
297 unsigned int ctl_in; /* cached input-pin control value */
298};
299
Takashi Iwaid922b512011-04-28 12:18:53 +0200300enum {
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200301 ALC_AUTOMUTE_PIN, /* change the pin control */
302 ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */
303 ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */
Takashi Iwaid922b512011-04-28 12:18:53 +0200304};
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306struct alc_spec {
307 /* codec parameterization */
Takashi Iwaia9111322011-05-02 11:30:18 +0200308 const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 unsigned int num_mixers;
Takashi Iwaia9111322011-05-02 11:30:18 +0200310 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Takashi Iwai45bdd1c2009-02-06 16:11:25 +0100311 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Takashi Iwai2d9c6482009-10-13 08:06:55 +0200313 const struct hda_verb *init_verbs[10]; /* initialization verbs
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200314 * don't forget NULL
315 * termination!
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200316 */
317 unsigned int num_init_verbs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200319 char stream_name_analog[32]; /* analog PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200320 const struct hda_pcm_stream *stream_analog_playback;
321 const struct hda_pcm_stream *stream_analog_capture;
322 const struct hda_pcm_stream *stream_analog_alt_playback;
323 const struct hda_pcm_stream *stream_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Takashi Iwaiaa563af2009-07-31 10:05:11 +0200325 char stream_name_digital[32]; /* digital PCM stream */
Takashi Iwaia9111322011-05-02 11:30:18 +0200326 const struct hda_pcm_stream *stream_digital_playback;
327 const struct hda_pcm_stream *stream_digital_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 /* playback */
Takashi Iwai16ded522005-06-10 19:58:24 +0200330 struct hda_multi_out multiout; /* playback set-up
331 * max_channels, dacs must be set
332 * dig_out_nid and hp_nid are optional
333 */
Takashi Iwai63300792008-01-24 15:31:36 +0100334 hda_nid_t alt_dac_nid;
Takashi Iwai6a05ac42009-02-13 11:19:09 +0100335 hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */
Takashi Iwai8c441982009-01-20 18:30:20 +0100336 int dig_out_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 /* capture */
339 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200340 const hda_nid_t *adc_nids;
341 const hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200342 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Takashi Iwai1f0f4b82011-06-27 10:52:59 +0200343 hda_nid_t mixer_nid; /* analog-mixer NID */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Takashi Iwai840b64c2010-07-13 22:49:01 +0200345 /* capture setup for dynamic dual-adc switch */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200346 hda_nid_t cur_adc;
347 unsigned int cur_adc_stream_tag;
348 unsigned int cur_adc_format;
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 /* capture source */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200351 unsigned int num_mux_defs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 const struct hda_input_mux *input_mux;
353 unsigned int cur_mux[3];
Takashi Iwai21268962011-07-07 15:01:13 +0200354 hda_nid_t ext_mic_pin;
355 hda_nid_t dock_mic_pin;
356 hda_nid_t int_mic_pin;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100359 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200361 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200362 int const_channel_count;
363 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100366 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200367
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200368 /* dynamic controls, init_verbs and input_mux */
369 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100370 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200371 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200372 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200373 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200374 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
375 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai21268962011-07-07 15:01:13 +0200376 hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
377 unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
378 int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
Takashi Iwai834be882006-03-01 14:16:17 +0100379
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100380 /* hooks */
381 void (*init_hook)(struct hda_codec *codec);
382 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100383#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500384 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100385#endif
Takashi Iwai1c716152011-04-07 10:37:16 +0200386 void (*shutup)(struct hda_codec *codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100387
Takashi Iwai834be882006-03-01 14:16:17 +0100388 /* for pin sensing */
Takashi Iwai834be882006-03-01 14:16:17 +0100389 unsigned int jack_present: 1;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200390 unsigned int line_jack_present:1;
Takashi Iwaie9427962011-04-28 15:46:07 +0200391 unsigned int master_mute:1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200392 unsigned int auto_mic:1;
Takashi Iwai21268962011-07-07 15:01:13 +0200393 unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */
Takashi Iwaid922b512011-04-28 12:18:53 +0200394 unsigned int automute:1; /* HP automute enabled */
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +0200395 unsigned int detect_line:1; /* Line-out detection enabled */
396 unsigned int automute_lines:1; /* automute line-out as well */
Takashi Iwaiae8a60a2011-04-28 18:09:52 +0200397 unsigned int automute_hp_lo:1; /* both HP and LO available */
Takashi Iwaicb53c622007-08-10 17:21:45 +0200398
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100399 /* other flags */
400 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai21268962011-07-07 15:01:13 +0200401 unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai584c0c42011-03-10 12:51:11 +0100402 unsigned int single_input_src:1;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +0200403 unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
Takashi Iwaid922b512011-04-28 12:18:53 +0200404
405 /* auto-mute control */
406 int automute_mode;
Takashi Iwai3b8510c2011-04-28 14:03:24 +0200407 hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
Takashi Iwaid922b512011-04-28 12:18:53 +0200408
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200409 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200410 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100411
Takashi Iwai2134ea42008-01-10 16:53:55 +0100412 /* for virtual master */
413 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200414#ifdef CONFIG_SND_HDA_POWER_SAVE
415 struct hda_loopback_check loopback;
416#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200417
418 /* for PLL fix */
419 hda_nid_t pll_nid;
420 unsigned int pll_coef_idx, pll_coef_bit;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +0100421
422 /* fix-up list */
423 int fixup_id;
424 const struct alc_fixup *fixup_list;
425 const char *fixup_name;
Takashi Iwaice764ab2011-04-27 16:35:23 +0200426
427 /* multi-io */
428 int multi_ios;
429 struct alc_multi_io multi_io[4];
Kailang Yangdf694da2005-12-05 19:42:22 +0100430};
431
432/*
433 * configuration template - to be copied to the spec instance
434 */
435struct alc_config_preset {
Takashi Iwaia9111322011-05-02 11:30:18 +0200436 const struct snd_kcontrol_new *mixers[5]; /* should be identical size
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200437 * with spec
438 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200439 const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100440 const struct hda_verb *init_verbs[5];
441 unsigned int num_dacs;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200442 const hda_nid_t *dac_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100443 hda_nid_t dig_out_nid; /* optional */
444 hda_nid_t hp_nid; /* optional */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200445 const hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100446 unsigned int num_adc_nids;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +0200447 const hda_nid_t *adc_nids;
448 const hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100449 hda_nid_t dig_in_nid;
450 unsigned int num_channel_mode;
451 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200452 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200453 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200454 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100455 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100456 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200457 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100458 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200459#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +0200460 const struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500461 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200462#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463};
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466/*
467 * input MUX handling
468 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200469static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
470 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
473 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200474 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
475 if (mux_idx >= spec->num_mux_defs)
476 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100477 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
478 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200479 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200482static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
483 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
485 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
486 struct alc_spec *spec = codec->spec;
487 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
488
489 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
490 return 0;
491}
492
Takashi Iwai21268962011-07-07 15:01:13 +0200493static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
Takashi Iwai21268962011-07-07 15:01:13 +0200495 struct alc_spec *spec = codec->spec;
496 hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
497
498 if (spec->cur_adc && spec->cur_adc != new_adc) {
499 /* stream is running, let's swap the current ADC */
500 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
501 spec->cur_adc = new_adc;
502 snd_hda_codec_setup_stream(codec, new_adc,
503 spec->cur_adc_stream_tag, 0,
504 spec->cur_adc_format);
505 return true;
506 }
507 return false;
508}
509
510/* select the given imux item; either unmute exclusively or select the route */
511static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
512 unsigned int idx, bool force)
513{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100515 const struct hda_input_mux *imux;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100516 unsigned int mux_idx;
Takashi Iwai21268962011-07-07 15:01:13 +0200517 int i, type;
518 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Takashi Iwaicd896c32008-11-18 12:36:33 +0100520 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
521 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100522 if (!imux->num_items && mux_idx > 0)
523 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100524
Takashi Iwai21268962011-07-07 15:01:13 +0200525 if (idx >= imux->num_items)
526 idx = imux->num_items - 1;
527 if (spec->cur_mux[adc_idx] == idx && !force)
528 return 0;
529 spec->cur_mux[adc_idx] = idx;
530
531 if (spec->dyn_adc_switch) {
532 alc_dyn_adc_pcm_resetup(codec, idx);
533 adc_idx = spec->dyn_adc_idx[idx];
534 }
535
536 nid = spec->capsrc_nids ?
537 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
538
539 /* no selection? */
540 if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
541 return 1;
542
Takashi Iwaia22d5432009-07-27 12:54:26 +0200543 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200544 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100545 /* Matrix-mixer style (e.g. ALC882) */
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100546 for (i = 0; i < imux->num_items; i++) {
547 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
548 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
549 imux->items[i].index,
550 HDA_AMP_MUTE, v);
551 }
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100552 } else {
553 /* MUX style (e.g. ALC880) */
Takashi Iwai21268962011-07-07 15:01:13 +0200554 snd_hda_codec_write_cache(codec, nid, 0,
555 AC_VERB_SET_CONNECT_SEL,
556 imux->items[idx].index);
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100557 }
Takashi Iwai21268962011-07-07 15:01:13 +0200558 return 1;
559}
560
561static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
563{
564 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
565 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
566 return alc_mux_select(codec, adc_idx,
567 ucontrol->value.enumerated.item[0], false);
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100568}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570/*
571 * channel mode setting
572 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200573static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
574 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
576 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
577 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100578 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
579 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580}
581
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200582static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
583 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
585 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
586 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100587 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200588 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200589 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590}
591
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200592static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
593 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
595 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
596 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200597 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
598 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200599 &spec->ext_channel_count);
600 if (err >= 0 && !spec->const_channel_count) {
601 spec->multiout.max_channels = spec->ext_channel_count;
602 if (spec->need_dac_fix)
603 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
604 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200605 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100609 * Control the mode of pin widget settings via the mixer. "pc" is used
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300610 * instead of "%" to avoid consequences of accidentally treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100611 * being part of a format specifier. Maximum allowed length of a value is
612 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100613 *
614 * Note: some retasking pin complexes seem to ignore requests for input
615 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
616 * are requested. Therefore order this list so that this behaviour will not
617 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200618 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
619 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200620 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200621static const char * const alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100622 "Mic 50pc bias", "Mic 80pc bias",
623 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100624};
Takashi Iwaia9111322011-05-02 11:30:18 +0200625static const unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100626 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100627};
628/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200629 * in the pin being assumed to be exclusively an input or an output pin. In
630 * addition, "input" pins may or may not process the mic bias option
631 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
632 * accept requests for bias as of chip versions up to March 2006) and/or
633 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100634 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200635#define ALC_PIN_DIR_IN 0x00
636#define ALC_PIN_DIR_OUT 0x01
637#define ALC_PIN_DIR_INOUT 0x02
638#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
639#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100640
Kailang Yangea1fb292008-08-26 12:58:38 +0200641/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100642 * For each direction the minimum and maximum values are given.
643 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200644static const signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100645 { 0, 2 }, /* ALC_PIN_DIR_IN */
646 { 3, 4 }, /* ALC_PIN_DIR_OUT */
647 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200648 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
649 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100650};
651#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
652#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
653#define alc_pin_mode_n_items(_dir) \
654 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
655
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200656static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
657 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200658{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100659 unsigned int item_num = uinfo->value.enumerated.item;
660 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
661
662 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200663 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100664 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
665
666 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
667 item_num = alc_pin_mode_min(dir);
668 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200669 return 0;
670}
671
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200672static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
673 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200674{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100675 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200676 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
677 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100678 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200679 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200680 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
681 AC_VERB_GET_PIN_WIDGET_CONTROL,
682 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200683
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100684 /* Find enumerated value for current pinctl setting */
685 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200686 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100687 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200688 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100689 return 0;
690}
691
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200692static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
693 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100694{
695 signed int change;
696 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
697 hda_nid_t nid = kcontrol->private_value & 0xffff;
698 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
699 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200700 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
701 AC_VERB_GET_PIN_WIDGET_CONTROL,
702 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100703
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200704 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100705 val = alc_pin_mode_min(dir);
706
707 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100708 if (change) {
709 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200710 snd_hda_codec_write_cache(codec, nid, 0,
711 AC_VERB_SET_PIN_WIDGET_CONTROL,
712 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100713
Kailang Yangea1fb292008-08-26 12:58:38 +0200714 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100715 * for the requested pin mode. Enum values of 2 or less are
716 * input modes.
717 *
718 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200719 * reduces noise slightly (particularly on input) so we'll
720 * do it. However, having both input and output buffers
721 * enabled simultaneously doesn't seem to be problematic if
722 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100723 */
724 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200725 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
726 HDA_AMP_MUTE, HDA_AMP_MUTE);
727 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
728 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100729 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200730 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
731 HDA_AMP_MUTE, HDA_AMP_MUTE);
732 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
733 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100734 }
735 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200736 return change;
737}
738
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100739#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200740 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100741 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100742 .info = alc_pin_mode_info, \
743 .get = alc_pin_mode_get, \
744 .put = alc_pin_mode_put, \
745 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100746
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100747/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
748 * together using a mask with more than one bit set. This control is
749 * currently used only by the ALC260 test model. At this stage they are not
750 * needed for any "production" models.
751 */
752#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200753#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200754
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200755static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
756 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100757{
758 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
759 hda_nid_t nid = kcontrol->private_value & 0xffff;
760 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
761 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200762 unsigned int val = snd_hda_codec_read(codec, nid, 0,
763 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100764
765 *valp = (val & mask) != 0;
766 return 0;
767}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200768static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
769 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100770{
771 signed int change;
772 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
773 hda_nid_t nid = kcontrol->private_value & 0xffff;
774 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
775 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200776 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
777 AC_VERB_GET_GPIO_DATA,
778 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100779
780 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200781 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
782 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100783 gpio_data &= ~mask;
784 else
785 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200786 snd_hda_codec_write_cache(codec, nid, 0,
787 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100788
789 return change;
790}
791#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
792 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100793 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100794 .info = alc_gpio_data_info, \
795 .get = alc_gpio_data_get, \
796 .put = alc_gpio_data_put, \
797 .private_value = nid | (mask<<16) }
798#endif /* CONFIG_SND_DEBUG */
799
Jonathan Woithe92621f12006-02-28 11:47:47 +0100800/* A switch control to allow the enabling of the digital IO pins on the
801 * ALC260. This is incredibly simplistic; the intention of this control is
802 * to provide something in the test model allowing digital outputs to be
803 * identified if present. If models are found which can utilise these
804 * outputs a more complete mixer control can be devised for those models if
805 * necessary.
806 */
807#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200808#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200809
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200810static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
811 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100812{
813 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
814 hda_nid_t nid = kcontrol->private_value & 0xffff;
815 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
816 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200817 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100818 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100819
820 *valp = (val & mask) != 0;
821 return 0;
822}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200823static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
824 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100825{
826 signed int change;
827 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
828 hda_nid_t nid = kcontrol->private_value & 0xffff;
829 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
830 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200831 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100832 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200833 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100834
835 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200836 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100837 if (val==0)
838 ctrl_data &= ~mask;
839 else
840 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200841 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
842 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100843
844 return change;
845}
846#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
847 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100848 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100849 .info = alc_spdif_ctrl_info, \
850 .get = alc_spdif_ctrl_get, \
851 .put = alc_spdif_ctrl_put, \
852 .private_value = nid | (mask<<16) }
853#endif /* CONFIG_SND_DEBUG */
854
Jonathan Woithef8225f62008-01-08 12:16:54 +0100855/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
856 * Again, this is only used in the ALC26x test models to help identify when
857 * the EAPD line must be asserted for features to work.
858 */
859#ifdef CONFIG_SND_DEBUG
860#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
861
862static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
863 struct snd_ctl_elem_value *ucontrol)
864{
865 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
866 hda_nid_t nid = kcontrol->private_value & 0xffff;
867 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
868 long *valp = ucontrol->value.integer.value;
869 unsigned int val = snd_hda_codec_read(codec, nid, 0,
870 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
871
872 *valp = (val & mask) != 0;
873 return 0;
874}
875
876static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
877 struct snd_ctl_elem_value *ucontrol)
878{
879 int change;
880 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
881 hda_nid_t nid = kcontrol->private_value & 0xffff;
882 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
883 long val = *ucontrol->value.integer.value;
884 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
885 AC_VERB_GET_EAPD_BTLENABLE,
886 0x00);
887
888 /* Set/unset the masked control bit(s) as needed */
889 change = (!val ? 0 : mask) != (ctrl_data & mask);
890 if (!val)
891 ctrl_data &= ~mask;
892 else
893 ctrl_data |= mask;
894 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
895 ctrl_data);
896
897 return change;
898}
899
900#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
901 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100902 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100903 .info = alc_eapd_ctrl_info, \
904 .get = alc_eapd_ctrl_get, \
905 .put = alc_eapd_ctrl_put, \
906 .private_value = nid | (mask<<16) }
907#endif /* CONFIG_SND_DEBUG */
908
Kailang Yangdf694da2005-12-05 19:42:22 +0100909/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100910 * set up the input pin config (depending on the given auto-pin type)
911 */
912static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
913 int auto_pin_type)
914{
915 unsigned int val = PIN_IN;
916
Takashi Iwai86e29592010-09-09 14:50:17 +0200917 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100918 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200919 unsigned int oldval;
920 oldval = snd_hda_codec_read(codec, nid, 0,
921 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100922 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100923 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200924 /* if the default pin setup is vref50, we give it priority */
925 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100926 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200927 else if (pincap & AC_PINCAP_VREF_50)
928 val = PIN_VREF50;
929 else if (pincap & AC_PINCAP_VREF_100)
930 val = PIN_VREF100;
931 else if (pincap & AC_PINCAP_VREF_GRD)
932 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100933 }
934 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
935}
936
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200937static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
938{
939 struct alc_spec *spec = codec->spec;
940 struct auto_pin_cfg *cfg = &spec->autocfg;
941
942 if (!cfg->line_outs) {
943 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
944 cfg->line_out_pins[cfg->line_outs])
945 cfg->line_outs++;
946 }
947 if (!cfg->speaker_outs) {
948 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
949 cfg->speaker_pins[cfg->speaker_outs])
950 cfg->speaker_outs++;
951 }
952 if (!cfg->hp_outs) {
953 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
954 cfg->hp_pins[cfg->hp_outs])
955 cfg->hp_outs++;
956 }
957}
958
Takashi Iwai23f0c042009-02-26 13:03:58 +0100959/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100960 */
Takashi Iwaia9111322011-05-02 11:30:18 +0200961static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100962{
963 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
964 return;
965 spec->mixers[spec->num_mixers++] = mix;
966}
967
968static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
969{
970 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
971 return;
972 spec->init_verbs[spec->num_init_verbs++] = verb;
973}
974
975/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100976 * set up from the preset table
977 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200978static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200979 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100980{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200981 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100982 int i;
983
984 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100985 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100986 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200987 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
988 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100989 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200990
Kailang Yangdf694da2005-12-05 19:42:22 +0100991 spec->channel_mode = preset->channel_mode;
992 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200993 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200994 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100995
Hector Martin3b315d72009-06-02 10:54:19 +0200996 if (preset->const_channel_count)
997 spec->multiout.max_channels = preset->const_channel_count;
998 else
999 spec->multiout.max_channels = spec->channel_mode[0].channels;
1000 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +01001001
1002 spec->multiout.num_dacs = preset->num_dacs;
1003 spec->multiout.dac_nids = preset->dac_nids;
1004 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08001005 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +01001006 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +02001007
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02001008 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02001009 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02001010 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +01001011 spec->input_mux = preset->input_mux;
1012
1013 spec->num_adc_nids = preset->num_adc_nids;
1014 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +01001015 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +01001016 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01001017
1018 spec->unsol_event = preset->unsol_event;
1019 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001020#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01001021 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +02001022 spec->loopback.amplist = preset->loopbacks;
1023#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +02001024
1025 if (preset->setup)
1026 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +02001027
1028 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01001029}
1030
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001031/* Enable GPIO mask and set output */
Takashi Iwaia9111322011-05-02 11:30:18 +02001032static const struct hda_verb alc_gpio1_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001033 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
1034 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
1035 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
1036 { }
1037};
1038
Takashi Iwaia9111322011-05-02 11:30:18 +02001039static const struct hda_verb alc_gpio2_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001040 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
1041 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
1042 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
1043 { }
1044};
1045
Takashi Iwaia9111322011-05-02 11:30:18 +02001046static const struct hda_verb alc_gpio3_init_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02001047 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
1048 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
1049 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
1050 { }
1051};
1052
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02001053/*
1054 * Fix hardware PLL issue
1055 * On some codecs, the analog PLL gating control must be off while
1056 * the default value is 1.
1057 */
1058static void alc_fix_pll(struct hda_codec *codec)
1059{
1060 struct alc_spec *spec = codec->spec;
1061 unsigned int val;
1062
1063 if (!spec->pll_nid)
1064 return;
1065 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1066 spec->pll_coef_idx);
1067 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1068 AC_VERB_GET_PROC_COEF, 0);
1069 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1070 spec->pll_coef_idx);
1071 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1072 val & ~(1 << spec->pll_coef_bit));
1073}
1074
1075static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1076 unsigned int coef_idx, unsigned int coef_bit)
1077{
1078 struct alc_spec *spec = codec->spec;
1079 spec->pll_nid = nid;
1080 spec->pll_coef_idx = coef_idx;
1081 spec->pll_coef_bit = coef_bit;
1082 alc_fix_pll(codec);
1083}
1084
Kailang Yang9ad0e492010-09-14 23:22:00 +02001085static int alc_init_jacks(struct hda_codec *codec)
1086{
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001087#ifdef CONFIG_SND_HDA_INPUT_JACK
Kailang Yang9ad0e492010-09-14 23:22:00 +02001088 struct alc_spec *spec = codec->spec;
1089 int err;
1090 unsigned int hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai21268962011-07-07 15:01:13 +02001091 unsigned int mic_nid = spec->ext_mic_pin;
1092 unsigned int dock_nid = spec->dock_mic_pin;
Kailang Yang9ad0e492010-09-14 23:22:00 +02001093
Takashi Iwai265a0242010-09-21 11:26:21 +02001094 if (hp_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001095 err = snd_hda_input_jack_add(codec, hp_nid,
1096 SND_JACK_HEADPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001097 if (err < 0)
1098 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001099 snd_hda_input_jack_report(codec, hp_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001100 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001101
Takashi Iwai265a0242010-09-21 11:26:21 +02001102 if (mic_nid) {
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001103 err = snd_hda_input_jack_add(codec, mic_nid,
1104 SND_JACK_MICROPHONE, NULL);
Takashi Iwai265a0242010-09-21 11:26:21 +02001105 if (err < 0)
1106 return err;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001107 snd_hda_input_jack_report(codec, mic_nid);
Takashi Iwai265a0242010-09-21 11:26:21 +02001108 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001109 if (dock_nid) {
1110 err = snd_hda_input_jack_add(codec, dock_nid,
1111 SND_JACK_MICROPHONE, NULL);
1112 if (err < 0)
1113 return err;
1114 snd_hda_input_jack_report(codec, dock_nid);
1115 }
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001116#endif /* CONFIG_SND_HDA_INPUT_JACK */
Kailang Yang9ad0e492010-09-14 23:22:00 +02001117 return 0;
1118}
Kailang Yang9ad0e492010-09-14 23:22:00 +02001119
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001120static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
Kailang Yangc9b58002007-10-16 14:30:01 +02001121{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001122 int i, present = 0;
Kailang Yangc9b58002007-10-16 14:30:01 +02001123
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001124 for (i = 0; i < num_pins; i++) {
1125 hda_nid_t nid = pins[i];
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001126 if (!nid)
1127 break;
Takashi Iwaicd372fb2011-03-03 14:40:14 +01001128 snd_hda_input_jack_report(codec, nid);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001129 present |= snd_hda_jack_detect(codec, nid);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001130 }
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001131 return present;
1132}
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001133
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001134static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
Takashi Iwaie9427962011-04-28 15:46:07 +02001135 bool mute, bool hp_out)
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001136{
1137 struct alc_spec *spec = codec->spec;
1138 unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02001139 unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001140 int i;
1141
1142 for (i = 0; i < num_pins; i++) {
1143 hda_nid_t nid = pins[i];
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001144 if (!nid)
1145 break;
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001146 switch (spec->automute_mode) {
1147 case ALC_AUTOMUTE_PIN:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001148 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001149 AC_VERB_SET_PIN_WIDGET_CONTROL,
1150 pin_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001151 break;
1152 case ALC_AUTOMUTE_AMP:
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001153 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001154 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001155 break;
1156 case ALC_AUTOMUTE_MIXER:
1157 nid = spec->automute_mixer_nid[i];
1158 if (!nid)
1159 break;
1160 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001161 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001162 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001163 HDA_AMP_MUTE, mute_bits);
Takashi Iwai3b8510c2011-04-28 14:03:24 +02001164 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001165 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001166 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001167}
1168
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001169/* Toggle internal speakers muting */
1170static void update_speakers(struct hda_codec *codec)
1171{
1172 struct alc_spec *spec = codec->spec;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001173 int on;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001174
Takashi Iwaic0a20262011-06-10 15:28:15 +02001175 /* Control HP pins/amps depending on master_mute state;
1176 * in general, HP pins/amps control should be enabled in all cases,
1177 * but currently set only for master_mute, just to be safe
1178 */
1179 do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1180 spec->autocfg.hp_pins, spec->master_mute, true);
1181
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001182 if (!spec->automute)
1183 on = 0;
1184 else
1185 on = spec->jack_present | spec->line_jack_present;
1186 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001187 do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001188 spec->autocfg.speaker_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001189
1190 /* toggle line-out mutes if needed, too */
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001191 /* if LO is a copy of either HP or Speaker, don't need to handle it */
1192 if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
1193 spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001194 return;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001195 if (!spec->automute_lines || !spec->automute)
1196 on = 0;
1197 else
1198 on = spec->jack_present;
1199 on |= spec->master_mute;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001200 do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001201 spec->autocfg.line_out_pins, on, false);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001202}
1203
1204static void alc_hp_automute(struct hda_codec *codec)
1205{
1206 struct alc_spec *spec = codec->spec;
1207
1208 if (!spec->automute)
1209 return;
1210 spec->jack_present =
1211 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
1212 spec->autocfg.hp_pins);
1213 update_speakers(codec);
1214}
1215
1216static void alc_line_automute(struct hda_codec *codec)
1217{
1218 struct alc_spec *spec = codec->spec;
1219
1220 if (!spec->automute || !spec->detect_line)
1221 return;
1222 spec->line_jack_present =
1223 detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
1224 spec->autocfg.line_out_pins);
1225 update_speakers(codec);
1226}
1227
Takashi Iwai8d087c72011-06-28 12:45:47 +02001228#define get_connection_index(codec, mux, nid) \
1229 snd_hda_get_conn_index(codec, mux, nid, 0)
Takashi Iwai6c819492009-08-10 18:47:44 +02001230
Kailang Yang7fb0d782008-10-15 11:12:35 +02001231static void alc_mic_automute(struct hda_codec *codec)
1232{
1233 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02001234 hda_nid_t *pins = spec->imux_pins;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001235
Takashi Iwai21268962011-07-07 15:01:13 +02001236 if (!spec->auto_mic || !spec->auto_mic_valid_imux)
Takashi Iwai6c819492009-08-10 18:47:44 +02001237 return;
1238 if (snd_BUG_ON(!spec->adc_nids))
1239 return;
Takashi Iwai21268962011-07-07 15:01:13 +02001240 if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
Takashi Iwai840b64c2010-07-13 22:49:01 +02001241 return;
Takashi Iwai840b64c2010-07-13 22:49:01 +02001242
Takashi Iwai21268962011-07-07 15:01:13 +02001243 if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
1244 alc_mux_select(codec, 0, spec->ext_mic_idx, false);
1245 else if (spec->dock_mic_idx >= 0 &&
1246 snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
1247 alc_mux_select(codec, 0, spec->dock_mic_idx, false);
1248 else
1249 alc_mux_select(codec, 0, spec->int_mic_idx, false);
Takashi Iwai6c819492009-08-10 18:47:44 +02001250
Takashi Iwai21268962011-07-07 15:01:13 +02001251 snd_hda_input_jack_report(codec, pins[spec->ext_mic_idx]);
1252 if (spec->dock_mic_idx >= 0)
1253 snd_hda_input_jack_report(codec, pins[spec->dock_mic_idx]);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001254}
1255
Kailang Yangc9b58002007-10-16 14:30:01 +02001256/* unsolicited event for HP jack sensing */
1257static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1258{
1259 if (codec->vendor_id == 0x10ec0880)
1260 res >>= 28;
1261 else
1262 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001263 switch (res) {
1264 case ALC880_HP_EVENT:
Takashi Iwaid922b512011-04-28 12:18:53 +02001265 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001266 break;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001267 case ALC880_FRONT_EVENT:
1268 alc_line_automute(codec);
1269 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001270 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001271 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001272 break;
1273 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001274}
1275
1276static void alc_inithook(struct hda_codec *codec)
1277{
Takashi Iwaid922b512011-04-28 12:18:53 +02001278 alc_hp_automute(codec);
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02001279 alc_line_automute(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001280 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001281}
1282
Kailang Yangf9423e72008-05-27 12:32:25 +02001283/* additional initialization for ALC888 variants */
1284static void alc888_coef_init(struct hda_codec *codec)
1285{
1286 unsigned int tmp;
1287
1288 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1289 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1290 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001291 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001292 /* alc888S-VC */
1293 snd_hda_codec_read(codec, 0x20, 0,
1294 AC_VERB_SET_PROC_COEF, 0x830);
1295 else
1296 /* alc888-VB */
1297 snd_hda_codec_read(codec, 0x20, 0,
1298 AC_VERB_SET_PROC_COEF, 0x3030);
1299}
1300
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001301static void alc889_coef_init(struct hda_codec *codec)
1302{
1303 unsigned int tmp;
1304
1305 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1306 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1307 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1308 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1309}
1310
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001311/* turn on/off EAPD control (only if available) */
1312static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1313{
1314 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1315 return;
1316 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1317 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1318 on ? 2 : 0);
1319}
1320
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001321/* turn on/off EAPD controls of the codec */
1322static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
1323{
1324 /* We currently only handle front, HP */
Takashi Iwai39fa84e2011-06-27 15:28:57 +02001325 static hda_nid_t pins[] = {
1326 0x0f, 0x10, 0x14, 0x15, 0
1327 };
1328 hda_nid_t *p;
1329 for (p = pins; *p; p++)
1330 set_eapd(codec, *p, on);
Takashi Iwai691f1fc2011-04-07 10:31:43 +02001331}
1332
Takashi Iwai1c716152011-04-07 10:37:16 +02001333/* generic shutup callback;
1334 * just turning off EPAD and a little pause for avoiding pop-noise
1335 */
1336static void alc_eapd_shutup(struct hda_codec *codec)
1337{
1338 alc_auto_setup_eapd(codec, false);
1339 msleep(200);
1340}
1341
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001342static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001343{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001344 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001345
Takashi Iwai39fa84e2011-06-27 15:28:57 +02001346 alc_auto_setup_eapd(codec, true);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001347 switch (type) {
1348 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001349 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1350 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001351 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001352 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1353 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001354 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001355 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1356 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001357 case ALC_INIT_DEFAULT:
Kailang Yangc9b58002007-10-16 14:30:01 +02001358 switch (codec->vendor_id) {
1359 case 0x10ec0260:
1360 snd_hda_codec_write(codec, 0x1a, 0,
1361 AC_VERB_SET_COEF_INDEX, 7);
1362 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1363 AC_VERB_GET_PROC_COEF, 0);
1364 snd_hda_codec_write(codec, 0x1a, 0,
1365 AC_VERB_SET_COEF_INDEX, 7);
1366 snd_hda_codec_write(codec, 0x1a, 0,
1367 AC_VERB_SET_PROC_COEF,
1368 tmp | 0x2010);
1369 break;
1370 case 0x10ec0262:
1371 case 0x10ec0880:
1372 case 0x10ec0882:
1373 case 0x10ec0883:
1374 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001375 case 0x10ec0887:
Takashi Iwai20b67dd2011-03-23 22:54:32 +01001376 /*case 0x10ec0889:*/ /* this causes an SPDIF problem */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001377 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001378 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001379 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001380 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001381 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001382#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001383 case 0x10ec0267:
1384 case 0x10ec0268:
1385 snd_hda_codec_write(codec, 0x20, 0,
1386 AC_VERB_SET_COEF_INDEX, 7);
1387 tmp = snd_hda_codec_read(codec, 0x20, 0,
1388 AC_VERB_GET_PROC_COEF, 0);
1389 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001390 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001391 snd_hda_codec_write(codec, 0x20, 0,
1392 AC_VERB_SET_PROC_COEF,
1393 tmp | 0x3000);
1394 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001395#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001396 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001397 break;
1398 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001399}
Kailang Yangea1fb292008-08-26 12:58:38 +02001400
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001401static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
1402 struct snd_ctl_elem_info *uinfo)
1403{
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001404 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1405 struct alc_spec *spec = codec->spec;
1406 static const char * const texts2[] = {
1407 "Disabled", "Enabled"
1408 };
1409 static const char * const texts3[] = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001410 "Disabled", "Speaker Only", "Line-Out+Speaker"
1411 };
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001412 const char * const *texts;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001413
1414 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1415 uinfo->count = 1;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001416 if (spec->automute_hp_lo) {
1417 uinfo->value.enumerated.items = 3;
1418 texts = texts3;
1419 } else {
1420 uinfo->value.enumerated.items = 2;
1421 texts = texts2;
1422 }
1423 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
1424 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001425 strcpy(uinfo->value.enumerated.name,
1426 texts[uinfo->value.enumerated.item]);
1427 return 0;
1428}
1429
1430static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
1431 struct snd_ctl_elem_value *ucontrol)
1432{
1433 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1434 struct alc_spec *spec = codec->spec;
1435 unsigned int val;
1436 if (!spec->automute)
1437 val = 0;
1438 else if (!spec->automute_lines)
1439 val = 1;
1440 else
1441 val = 2;
1442 ucontrol->value.enumerated.item[0] = val;
1443 return 0;
1444}
1445
1446static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
1447 struct snd_ctl_elem_value *ucontrol)
1448{
1449 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1450 struct alc_spec *spec = codec->spec;
1451
1452 switch (ucontrol->value.enumerated.item[0]) {
1453 case 0:
1454 if (!spec->automute)
1455 return 0;
1456 spec->automute = 0;
1457 break;
1458 case 1:
1459 if (spec->automute && !spec->automute_lines)
1460 return 0;
1461 spec->automute = 1;
1462 spec->automute_lines = 0;
1463 break;
1464 case 2:
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001465 if (!spec->automute_hp_lo)
1466 return -EINVAL;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001467 if (spec->automute && spec->automute_lines)
1468 return 0;
1469 spec->automute = 1;
1470 spec->automute_lines = 1;
1471 break;
1472 default:
1473 return -EINVAL;
1474 }
1475 update_speakers(codec);
1476 return 1;
1477}
1478
Takashi Iwaia9111322011-05-02 11:30:18 +02001479static const struct snd_kcontrol_new alc_automute_mode_enum = {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001480 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1481 .name = "Auto-Mute Mode",
1482 .info = alc_automute_mode_info,
1483 .get = alc_automute_mode_get,
1484 .put = alc_automute_mode_put,
1485};
1486
1487static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec);
1488
1489static int alc_add_automute_mode_enum(struct hda_codec *codec)
1490{
1491 struct alc_spec *spec = codec->spec;
1492 struct snd_kcontrol_new *knew;
1493
1494 knew = alc_kcontrol_new(spec);
1495 if (!knew)
1496 return -ENOMEM;
1497 *knew = alc_automute_mode_enum;
1498 knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
1499 if (!knew->name)
1500 return -ENOMEM;
1501 return 0;
1502}
1503
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001504static void alc_init_auto_hp(struct hda_codec *codec)
1505{
1506 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001507 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001508 int present = 0;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001509 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001510
Takashi Iwai1daf5f42011-04-28 17:57:46 +02001511 if (cfg->hp_pins[0])
1512 present++;
1513 if (cfg->line_out_pins[0])
1514 present++;
1515 if (cfg->speaker_pins[0])
1516 present++;
1517 if (present < 2) /* need two different output types */
1518 return;
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001519 if (present == 3)
1520 spec->automute_hp_lo = 1; /* both HP and LO automute */
Kailang Yangc9b58002007-10-16 14:30:01 +02001521
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001522 if (!cfg->speaker_pins[0]) {
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001523 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1524 sizeof(cfg->speaker_pins));
1525 cfg->speaker_outs = cfg->line_outs;
1526 }
1527
1528 if (!cfg->hp_pins[0]) {
1529 memcpy(cfg->hp_pins, cfg->line_out_pins,
1530 sizeof(cfg->hp_pins));
1531 cfg->hp_outs = cfg->line_outs;
1532 }
1533
1534 for (i = 0; i < cfg->hp_outs; i++) {
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001535 hda_nid_t nid = cfg->hp_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001536 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001537 continue;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001538 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001539 nid);
1540 snd_hda_codec_write_cache(codec, nid, 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001541 AC_VERB_SET_UNSOLICITED_ENABLE,
1542 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaid922b512011-04-28 12:18:53 +02001543 spec->automute = 1;
1544 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001545 }
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001546 if (spec->automute && cfg->line_out_pins[0] &&
1547 cfg->line_out_pins[0] != cfg->hp_pins[0] &&
1548 cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
1549 for (i = 0; i < cfg->line_outs; i++) {
1550 hda_nid_t nid = cfg->line_out_pins[i];
Takashi Iwai06dec222011-05-17 10:00:16 +02001551 if (!is_jack_detectable(codec, nid))
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001552 continue;
1553 snd_printdd("realtek: Enable Line-Out auto-muting "
1554 "on NID 0x%x\n", nid);
1555 snd_hda_codec_write_cache(codec, nid, 0,
1556 AC_VERB_SET_UNSOLICITED_ENABLE,
1557 AC_USRSP_EN | ALC880_FRONT_EVENT);
1558 spec->detect_line = 1;
1559 }
Takashi Iwai52d3cb82011-05-17 10:04:08 +02001560 spec->automute_lines = spec->detect_line;
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001561 }
Takashi Iwaiae8a60a2011-04-28 18:09:52 +02001562
1563 if (spec->automute) {
1564 /* create a control for automute mode */
1565 alc_add_automute_mode_enum(codec);
1566 spec->unsol_event = alc_sku_unsol_event;
1567 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001568}
1569
Takashi Iwai21268962011-07-07 15:01:13 +02001570static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1571{
1572 int i;
1573 for (i = 0; i < nums; i++)
1574 if (list[i] == nid)
1575 return i;
1576 return -1;
1577}
1578
1579static bool alc_check_dyn_adc_switch(struct hda_codec *codec);
1580
1581/* rebuild imux for matching with the given auto-mic pins (if not yet) */
1582static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
1583{
1584 struct alc_spec *spec = codec->spec;
1585 struct hda_input_mux *imux;
1586 static char * const texts[3] = {
1587 "Mic", "Internal Mic", "Dock Mic"
1588 };
1589 int i;
1590
1591 if (!spec->auto_mic)
1592 return false;
1593 imux = &spec->private_imux[0];
1594 if (spec->input_mux == imux)
1595 return true;
1596 spec->imux_pins[0] = spec->ext_mic_pin;
1597 spec->imux_pins[1] = spec->int_mic_pin;
1598 spec->imux_pins[2] = spec->dock_mic_pin;
1599 for (i = 0; i < 3; i++) {
1600 strcpy(imux->items[i].label, texts[i]);
1601 if (spec->imux_pins[i])
1602 imux->num_items = i + 1;
1603 }
1604 spec->num_mux_defs = 1;
1605 spec->input_mux = imux;
1606 return true;
1607}
1608
1609/* check whether all auto-mic pins are valid; setup indices if OK */
1610static bool alc_auto_mic_check_imux(struct hda_codec *codec)
1611{
1612 struct alc_spec *spec = codec->spec;
1613 const struct hda_input_mux *imux;
1614
1615 if (!spec->auto_mic)
1616 return false;
1617 if (spec->auto_mic_valid_imux)
1618 return true; /* already checked */
1619
1620 /* fill up imux indices */
1621 if (!alc_check_dyn_adc_switch(codec)) {
1622 spec->auto_mic = 0;
1623 return false;
1624 }
1625
1626 imux = spec->input_mux;
1627 spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
1628 spec->imux_pins, imux->num_items);
1629 spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
1630 spec->imux_pins, imux->num_items);
1631 spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
1632 spec->imux_pins, imux->num_items);
1633 if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) {
1634 spec->auto_mic = 0;
1635 return false; /* no corresponding imux */
1636 }
1637
1638 snd_hda_codec_write_cache(codec, spec->ext_mic_pin, 0,
1639 AC_VERB_SET_UNSOLICITED_ENABLE,
1640 AC_USRSP_EN | ALC880_MIC_EVENT);
1641 if (spec->dock_mic_pin)
1642 snd_hda_codec_write_cache(codec, spec->dock_mic_pin, 0,
1643 AC_VERB_SET_UNSOLICITED_ENABLE,
1644 AC_USRSP_EN | ALC880_MIC_EVENT);
1645
1646 spec->auto_mic_valid_imux = 1;
1647 spec->auto_mic = 1;
1648 return true;
1649}
1650
Takashi Iwai6c819492009-08-10 18:47:44 +02001651static void alc_init_auto_mic(struct hda_codec *codec)
1652{
1653 struct alc_spec *spec = codec->spec;
1654 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001655 hda_nid_t fixed, ext, dock;
Takashi Iwai6c819492009-08-10 18:47:44 +02001656 int i;
1657
Takashi Iwai21268962011-07-07 15:01:13 +02001658 spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
1659
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001660 fixed = ext = dock = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001661 for (i = 0; i < cfg->num_inputs; i++) {
1662 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001663 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001664 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001665 switch (snd_hda_get_input_pin_attr(defcfg)) {
1666 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001667 if (fixed)
1668 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001669 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1670 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001671 fixed = nid;
1672 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001673 case INPUT_PIN_ATTR_UNUSED:
1674 return; /* invalid entry */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001675 case INPUT_PIN_ATTR_DOCK:
1676 if (dock)
1677 return; /* already occupied */
1678 if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
1679 return; /* invalid type */
1680 dock = nid;
1681 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001682 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001683 if (ext)
1684 return; /* already occupied */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001685 if (cfg->inputs[i].type != AUTO_PIN_MIC)
1686 return; /* invalid type */
Takashi Iwai6c819492009-08-10 18:47:44 +02001687 ext = nid;
1688 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001689 }
1690 }
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001691 if (!ext && dock) {
1692 ext = dock;
1693 dock = 0;
1694 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001695 if (!ext || !fixed)
1696 return;
Takashi Iwaie35d9d62011-05-17 11:28:16 +02001697 if (!is_jack_detectable(codec, ext))
Takashi Iwai6c819492009-08-10 18:47:44 +02001698 return; /* no unsol support */
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001699 if (dock && !is_jack_detectable(codec, dock))
1700 return; /* no unsol support */
Takashi Iwai21268962011-07-07 15:01:13 +02001701
1702 /* check imux indices */
1703 spec->ext_mic_pin = ext;
1704 spec->int_mic_pin = fixed;
1705 spec->dock_mic_pin = dock;
1706
1707 spec->auto_mic = 1;
1708 if (!alc_auto_mic_check_imux(codec))
1709 return;
1710
Takashi Iwai8ed99d92011-05-17 12:05:02 +02001711 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
1712 ext, fixed, dock);
Takashi Iwai6c819492009-08-10 18:47:44 +02001713 spec->unsol_event = alc_sku_unsol_event;
1714}
1715
David Henningsson90622912010-10-14 14:50:18 +02001716/* Could be any non-zero and even value. When used as fixup, tells
1717 * the driver to ignore any present sku defines.
1718 */
1719#define ALC_FIXUP_SKU_IGNORE (2)
1720
Kailang Yangda00c242010-03-19 11:23:45 +01001721static int alc_auto_parse_customize_define(struct hda_codec *codec)
1722{
1723 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001724 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001725 struct alc_spec *spec = codec->spec;
1726
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001727 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1728
David Henningsson90622912010-10-14 14:50:18 +02001729 if (spec->cdefine.fixup) {
1730 ass = spec->cdefine.sku_cfg;
1731 if (ass == ALC_FIXUP_SKU_IGNORE)
1732 return -1;
1733 goto do_sku;
1734 }
1735
Kailang Yangda00c242010-03-19 11:23:45 +01001736 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001737 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001738 goto do_sku;
1739
1740 nid = 0x1d;
1741 if (codec->vendor_id == 0x10ec0260)
1742 nid = 0x17;
1743 ass = snd_hda_codec_get_pincfg(codec, nid);
1744
1745 if (!(ass & 1)) {
1746 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1747 codec->chip_name, ass);
1748 return -1;
1749 }
1750
1751 /* check sum */
1752 tmp = 0;
1753 for (i = 1; i < 16; i++) {
1754 if ((ass >> i) & 1)
1755 tmp++;
1756 }
1757 if (((ass >> 16) & 0xf) != tmp)
1758 return -1;
1759
1760 spec->cdefine.port_connectivity = ass >> 30;
1761 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1762 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1763 spec->cdefine.customization = ass >> 8;
1764do_sku:
1765 spec->cdefine.sku_cfg = ass;
1766 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1767 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1768 spec->cdefine.swap = (ass & 0x2) >> 1;
1769 spec->cdefine.override = ass & 0x1;
1770
1771 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1772 nid, spec->cdefine.sku_cfg);
1773 snd_printd("SKU: port_connectivity=0x%x\n",
1774 spec->cdefine.port_connectivity);
1775 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1776 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1777 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1778 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1779 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1780 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1781 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1782
1783 return 0;
1784}
1785
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001786static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
1787{
Takashi Iwai21268962011-07-07 15:01:13 +02001788 return find_idx_in_nid_list(nid, list, nums) >= 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001789}
1790
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001791/* check subsystem ID and set up device-specific initialization;
1792 * return 1 if initialized, 0 if invalid SSID
1793 */
1794/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1795 * 31 ~ 16 : Manufacture ID
1796 * 15 ~ 8 : SKU ID
1797 * 7 ~ 0 : Assembly ID
1798 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1799 */
1800static int alc_subsystem_id(struct hda_codec *codec,
1801 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001802 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001803{
1804 unsigned int ass, tmp, i;
1805 unsigned nid;
1806 struct alc_spec *spec = codec->spec;
1807
David Henningsson90622912010-10-14 14:50:18 +02001808 if (spec->cdefine.fixup) {
1809 ass = spec->cdefine.sku_cfg;
1810 if (ass == ALC_FIXUP_SKU_IGNORE)
1811 return 0;
1812 goto do_sku;
1813 }
1814
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001815 ass = codec->subsystem_id & 0xffff;
1816 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1817 goto do_sku;
1818
1819 /* invalid SSID, check the special NID pin defcfg instead */
1820 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001821 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001822 * 29~21 : reserve
1823 * 20 : PCBEEP input
1824 * 19~16 : Check sum (15:1)
1825 * 15~1 : Custom
1826 * 0 : override
1827 */
1828 nid = 0x1d;
1829 if (codec->vendor_id == 0x10ec0260)
1830 nid = 0x17;
1831 ass = snd_hda_codec_get_pincfg(codec, nid);
1832 snd_printd("realtek: No valid SSID, "
1833 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001834 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001835 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001836 return 0;
1837 if ((ass >> 30) != 1) /* no physical connection */
1838 return 0;
1839
1840 /* check sum */
1841 tmp = 0;
1842 for (i = 1; i < 16; i++) {
1843 if ((ass >> i) & 1)
1844 tmp++;
1845 }
1846 if (((ass >> 16) & 0xf) != tmp)
1847 return 0;
1848do_sku:
1849 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1850 ass & 0xffff, codec->vendor_id);
1851 /*
1852 * 0 : override
1853 * 1 : Swap Jack
1854 * 2 : 0 --> Desktop, 1 --> Laptop
1855 * 3~5 : External Amplifier control
1856 * 7~6 : Reserved
1857 */
1858 tmp = (ass & 0x38) >> 3; /* external Amp control */
1859 switch (tmp) {
1860 case 1:
1861 spec->init_amp = ALC_INIT_GPIO1;
1862 break;
1863 case 3:
1864 spec->init_amp = ALC_INIT_GPIO2;
1865 break;
1866 case 7:
1867 spec->init_amp = ALC_INIT_GPIO3;
1868 break;
1869 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001870 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001871 spec->init_amp = ALC_INIT_DEFAULT;
1872 break;
1873 }
1874
1875 /* is laptop or Desktop and enable the function "Mute internal speaker
1876 * when the external headphone out jack is plugged"
1877 */
1878 if (!(ass & 0x8000))
1879 return 1;
1880 /*
1881 * 10~8 : Jack location
1882 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1883 * 14~13: Resvered
1884 * 15 : 1 --> enable the function "Mute internal speaker
1885 * when the external headphone out jack is plugged"
1886 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001887 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001888 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001889 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1890 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001891 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001892 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001893 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001894 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001895 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001896 else if (tmp == 3)
1897 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001898 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001899 return 1;
Takashi Iwai3af9ee62011-06-27 12:34:01 +02001900 if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
1901 spec->autocfg.line_outs))
1902 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001903 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001904 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001905 return 1;
1906}
Kailang Yangea1fb292008-08-26 12:58:38 +02001907
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001908static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001909 hda_nid_t porta, hda_nid_t porte,
1910 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001911{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001912 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001913 struct alc_spec *spec = codec->spec;
1914 snd_printd("realtek: "
1915 "Enable default setup for auto mode as fallback\n");
1916 spec->init_amp = ALC_INIT_DEFAULT;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001917 }
Takashi Iwai21268962011-07-07 15:01:13 +02001918}
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001919
Takashi Iwai21268962011-07-07 15:01:13 +02001920/* check the availabilities of auto-mute and auto-mic switches */
1921static void alc_auto_check_switches(struct hda_codec *codec)
1922{
Takashi Iwai1a1455d2011-04-28 17:36:18 +02001923 alc_init_auto_hp(codec);
1924 alc_init_auto_mic(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001925}
1926
Takashi Iwai41e41f12005-06-08 14:48:49 +02001927/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001928 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001929 */
1930
1931struct alc_pincfg {
1932 hda_nid_t nid;
1933 u32 val;
1934};
1935
Todd Broche1eb5f12010-12-06 11:19:51 -08001936struct alc_model_fixup {
1937 const int id;
1938 const char *name;
1939};
1940
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001941struct alc_fixup {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001942 int type;
Takashi Iwai361fe6e2011-01-14 09:55:32 +01001943 bool chained;
1944 int chain_id;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001945 union {
1946 unsigned int sku;
1947 const struct alc_pincfg *pins;
1948 const struct hda_verb *verbs;
1949 void (*func)(struct hda_codec *codec,
1950 const struct alc_fixup *fix,
1951 int action);
1952 } v;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001953};
1954
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001955enum {
1956 ALC_FIXUP_INVALID,
1957 ALC_FIXUP_SKU,
1958 ALC_FIXUP_PINS,
1959 ALC_FIXUP_VERBS,
1960 ALC_FIXUP_FUNC,
1961};
Takashi Iwaif95474e2007-07-10 00:47:43 +02001962
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001963enum {
1964 ALC_FIXUP_ACT_PRE_PROBE,
1965 ALC_FIXUP_ACT_PROBE,
Takashi Iwai58701122011-01-13 15:41:45 +01001966 ALC_FIXUP_ACT_INIT,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001967};
1968
1969static void alc_apply_fixup(struct hda_codec *codec, int action)
1970{
1971 struct alc_spec *spec = codec->spec;
1972 int id = spec->fixup_id;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001973#ifdef CONFIG_SND_DEBUG_VERBOSE
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001974 const char *modelname = spec->fixup_name;
Takashi Iwaiaa1d0c52011-01-19 17:27:58 +01001975#endif
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01001976 int depth = 0;
1977
1978 if (!spec->fixup_list)
1979 return;
1980
1981 while (id >= 0) {
1982 const struct alc_fixup *fix = spec->fixup_list + id;
1983 const struct alc_pincfg *cfg;
1984
1985 switch (fix->type) {
1986 case ALC_FIXUP_SKU:
1987 if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
1988 break;;
1989 snd_printdd(KERN_INFO "hda_codec: %s: "
1990 "Apply sku override for %s\n",
1991 codec->chip_name, modelname);
1992 spec->cdefine.sku_cfg = fix->v.sku;
1993 spec->cdefine.fixup = 1;
1994 break;
1995 case ALC_FIXUP_PINS:
1996 cfg = fix->v.pins;
1997 if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
1998 break;
1999 snd_printdd(KERN_INFO "hda_codec: %s: "
2000 "Apply pincfg for %s\n",
2001 codec->chip_name, modelname);
2002 for (; cfg->nid; cfg++)
2003 snd_hda_codec_set_pincfg(codec, cfg->nid,
2004 cfg->val);
2005 break;
2006 case ALC_FIXUP_VERBS:
2007 if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
2008 break;
2009 snd_printdd(KERN_INFO "hda_codec: %s: "
2010 "Apply fix-verbs for %s\n",
2011 codec->chip_name, modelname);
2012 add_verb(codec->spec, fix->v.verbs);
2013 break;
2014 case ALC_FIXUP_FUNC:
2015 if (!fix->v.func)
2016 break;
2017 snd_printdd(KERN_INFO "hda_codec: %s: "
2018 "Apply fix-func for %s\n",
2019 codec->chip_name, modelname);
2020 fix->v.func(codec, fix, action);
2021 break;
2022 default:
2023 snd_printk(KERN_ERR "hda_codec: %s: "
2024 "Invalid fixup type %d\n",
2025 codec->chip_name, fix->type);
2026 break;
2027 }
Takashi Iwai24af2b12011-05-02 13:55:36 +02002028 if (!fix->chained)
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002029 break;
2030 if (++depth > 10)
2031 break;
Takashi Iwai24af2b12011-05-02 13:55:36 +02002032 id = fix->chain_id;
Takashi Iwai9d578832010-11-22 13:29:19 +01002033 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002034}
2035
Todd Broche1eb5f12010-12-06 11:19:51 -08002036static void alc_pick_fixup(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002037 const struct alc_model_fixup *models,
2038 const struct snd_pci_quirk *quirk,
2039 const struct alc_fixup *fixlist)
Todd Broche1eb5f12010-12-06 11:19:51 -08002040{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002041 struct alc_spec *spec = codec->spec;
2042 int id = -1;
2043 const char *name = NULL;
Todd Broche1eb5f12010-12-06 11:19:51 -08002044
Todd Broche1eb5f12010-12-06 11:19:51 -08002045 if (codec->modelname && models) {
2046 while (models->name) {
2047 if (!strcmp(codec->modelname, models->name)) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002048 id = models->id;
2049 name = models->name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002050 break;
2051 }
2052 models++;
2053 }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01002054 }
2055 if (id < 0) {
2056 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
2057 if (quirk) {
2058 id = quirk->value;
2059#ifdef CONFIG_SND_DEBUG_VERBOSE
2060 name = quirk->name;
2061#endif
2062 }
2063 }
2064
2065 spec->fixup_id = id;
2066 if (id >= 0) {
2067 spec->fixup_list = fixlist;
2068 spec->fixup_name = name;
Todd Broche1eb5f12010-12-06 11:19:51 -08002069 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02002070}
2071
Kailang Yang274693f2009-12-03 10:07:50 +01002072static int alc_read_coef_idx(struct hda_codec *codec,
2073 unsigned int coef_idx)
2074{
2075 unsigned int val;
2076 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2077 coef_idx);
2078 val = snd_hda_codec_read(codec, 0x20, 0,
2079 AC_VERB_GET_PROC_COEF, 0);
2080 return val;
2081}
2082
Kailang Yang977ddd62010-09-15 10:02:29 +02002083static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
2084 unsigned int coef_val)
2085{
2086 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
2087 coef_idx);
2088 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
2089 coef_val);
2090}
2091
Takashi Iwai757899a2010-07-30 10:48:14 +02002092/* set right pin controls for digital I/O */
2093static void alc_auto_init_digital(struct hda_codec *codec)
2094{
2095 struct alc_spec *spec = codec->spec;
2096 int i;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002097 hda_nid_t pin, dac;
Takashi Iwai757899a2010-07-30 10:48:14 +02002098
2099 for (i = 0; i < spec->autocfg.dig_outs; i++) {
2100 pin = spec->autocfg.dig_out_pins[i];
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02002101 if (!pin)
2102 continue;
2103 snd_hda_codec_write(codec, pin, 0,
2104 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
2105 if (!i)
2106 dac = spec->multiout.dig_out_nid;
2107 else
2108 dac = spec->slave_dig_outs[i - 1];
2109 if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
2110 continue;
2111 snd_hda_codec_write(codec, dac, 0,
2112 AC_VERB_SET_AMP_GAIN_MUTE,
2113 AMP_OUT_UNMUTE);
Takashi Iwai757899a2010-07-30 10:48:14 +02002114 }
2115 pin = spec->autocfg.dig_in_pin;
2116 if (pin)
2117 snd_hda_codec_write(codec, pin, 0,
2118 AC_VERB_SET_PIN_WIDGET_CONTROL,
2119 PIN_IN);
2120}
2121
2122/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
2123static void alc_auto_parse_digital(struct hda_codec *codec)
2124{
2125 struct alc_spec *spec = codec->spec;
2126 int i, err;
2127 hda_nid_t dig_nid;
2128
2129 /* support multiple SPDIFs; the secondary is set up as a slave */
2130 for (i = 0; i < spec->autocfg.dig_outs; i++) {
Takashi Iwaia9267572011-07-07 15:12:55 +02002131 hda_nid_t conn[4];
Takashi Iwai757899a2010-07-30 10:48:14 +02002132 err = snd_hda_get_connections(codec,
2133 spec->autocfg.dig_out_pins[i],
Takashi Iwaia9267572011-07-07 15:12:55 +02002134 conn, ARRAY_SIZE(conn));
Takashi Iwai757899a2010-07-30 10:48:14 +02002135 if (err < 0)
2136 continue;
Takashi Iwaia9267572011-07-07 15:12:55 +02002137 dig_nid = conn[0]; /* assume the first element is audio-out */
Takashi Iwai757899a2010-07-30 10:48:14 +02002138 if (!i) {
2139 spec->multiout.dig_out_nid = dig_nid;
2140 spec->dig_out_type = spec->autocfg.dig_out_type[0];
2141 } else {
2142 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
2143 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
2144 break;
2145 spec->slave_dig_outs[i - 1] = dig_nid;
2146 }
2147 }
2148
2149 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02002150 dig_nid = codec->start_nid;
2151 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
2152 unsigned int wcaps = get_wcaps(codec, dig_nid);
2153 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
2154 continue;
2155 if (!(wcaps & AC_WCAP_DIGITAL))
2156 continue;
2157 if (!(wcaps & AC_WCAP_CONN_LIST))
2158 continue;
2159 err = get_connection_index(codec, dig_nid,
2160 spec->autocfg.dig_in_pin);
2161 if (err >= 0) {
2162 spec->dig_in_nid = dig_nid;
2163 break;
2164 }
2165 }
Takashi Iwai757899a2010-07-30 10:48:14 +02002166 }
2167}
2168
Takashi Iwaif95474e2007-07-10 00:47:43 +02002169/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002170 * ALC888
2171 */
2172
2173/*
2174 * 2ch mode
2175 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002176static const struct hda_verb alc888_4ST_ch2_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002177/* Mic-in jack as mic in */
2178 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2179 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2180/* Line-in jack as Line in */
2181 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2182 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2183/* Line-Out as Front */
2184 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2185 { } /* end */
2186};
2187
2188/*
2189 * 4ch mode
2190 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002191static const struct hda_verb alc888_4ST_ch4_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002192/* Mic-in jack as mic in */
2193 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2194 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2195/* Line-in jack as Surround */
2196 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2197 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2198/* Line-Out as Front */
2199 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
2200 { } /* end */
2201};
2202
2203/*
2204 * 6ch mode
2205 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002206static const struct hda_verb alc888_4ST_ch6_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002207/* Mic-in jack as CLFE */
2208 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2209 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2210/* Line-in jack as Surround */
2211 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2212 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2213/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
2214 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2215 { } /* end */
2216};
2217
2218/*
2219 * 8ch mode
2220 */
Takashi Iwaia9111322011-05-02 11:30:18 +02002221static const struct hda_verb alc888_4ST_ch8_intel_init[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002222/* Mic-in jack as CLFE */
2223 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2224 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2225/* Line-in jack as Surround */
2226 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2227 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2228/* Line-Out as Side */
2229 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2230 { } /* end */
2231};
2232
Takashi Iwaia9111322011-05-02 11:30:18 +02002233static const struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002234 { 2, alc888_4ST_ch2_intel_init },
2235 { 4, alc888_4ST_ch4_intel_init },
2236 { 6, alc888_4ST_ch6_intel_init },
2237 { 8, alc888_4ST_ch8_intel_init },
2238};
2239
2240/*
2241 * ALC888 Fujitsu Siemens Amillo xa3530
2242 */
2243
Takashi Iwaia9111322011-05-02 11:30:18 +02002244static const struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002245/* Front Mic: set to PIN_IN (empty by default) */
2246 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2247/* Connect Internal HP to Front */
2248 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2249 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2250 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2251/* Connect Bass HP to Front */
2252 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2253 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2254 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2255/* Connect Line-Out side jack (SPDIF) to Side */
2256 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2257 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2258 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
2259/* Connect Mic jack to CLFE */
2260 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2261 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2262 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
2263/* Connect Line-in jack to Surround */
2264 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2265 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2266 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
2267/* Connect HP out jack to Front */
2268 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2269 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2270 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
2271/* Enable unsolicited event for HP jack and Line-out jack */
2272 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2273 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2274 {}
2275};
2276
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002277static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02002278{
2279 struct alc_spec *spec = codec->spec;
2280
2281 spec->autocfg.hp_pins[0] = 0x15;
2282 spec->autocfg.speaker_pins[0] = 0x14;
2283 spec->autocfg.speaker_pins[1] = 0x16;
2284 spec->autocfg.speaker_pins[2] = 0x17;
2285 spec->autocfg.speaker_pins[3] = 0x19;
2286 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02002287 spec->automute = 1;
2288 spec->automute_mode = ALC_AUTOMUTE_AMP;
Wu Fengguang6732bd02009-07-30 09:19:14 +02002289}
2290
2291static void alc889_intel_init_hook(struct hda_codec *codec)
2292{
2293 alc889_coef_init(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02002294 alc_hp_automute(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02002295}
2296
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002297static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002298{
2299 struct alc_spec *spec = codec->spec;
2300
2301 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
2302 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
2303 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
2304 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaid922b512011-04-28 12:18:53 +02002305 spec->automute = 1;
2306 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002307}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002308
2309/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002310 * ALC888 Acer Aspire 4930G model
2311 */
2312
Takashi Iwaia9111322011-05-02 11:30:18 +02002313static const struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002314/* Front Mic: set to PIN_IN (empty by default) */
2315 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2316/* Unselect Front Mic by default in input mixer 3 */
2317 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002318/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002319 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2320/* Connect Internal HP to front */
2321 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2322 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2323 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2324/* Connect HP out to front */
2325 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2326 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2327 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie2e93292011-01-12 08:03:39 +01002328 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002329 { }
2330};
2331
Hector Martin3b315d72009-06-02 10:54:19 +02002332/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01002333 * ALC888 Acer Aspire 6530G model
2334 */
2335
Takashi Iwaia9111322011-05-02 11:30:18 +02002336static const struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01002337/* Route to built-in subwoofer as well as speakers */
2338 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2339 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2340 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2341 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002342/* Bias voltage on for external mic port */
2343 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02002344/* Front Mic: set to PIN_IN (empty by default) */
2345 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2346/* Unselect Front Mic by default in input mixer 3 */
2347 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002348/* Enable unsolicited event for HP jack */
2349 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2350/* Enable speaker output */
2351 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2352 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01002353 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002354/* Enable headphone output */
2355 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2356 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2357 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01002358 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002359 { }
2360};
2361
2362/*
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002363 *ALC888 Acer Aspire 7730G model
2364 */
2365
Takashi Iwaia9111322011-05-02 11:30:18 +02002366static const struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002367/* Bias voltage on for external mic port */
2368 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
2369/* Front Mic: set to PIN_IN (empty by default) */
2370 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2371/* Unselect Front Mic by default in input mixer 3 */
2372 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2373/* Enable unsolicited event for HP jack */
2374 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2375/* Enable speaker output */
2376 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2377 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2378 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
2379/* Enable headphone output */
2380 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2381 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2382 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2383 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
2384/*Enable internal subwoofer */
2385 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2386 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2387 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
2388 {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
2389 { }
2390};
2391
2392/*
Hector Martin018df412009-06-04 00:13:40 +02002393 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02002394 */
2395
Takashi Iwaia9111322011-05-02 11:30:18 +02002396static const struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02002397/* Front Mic: set to PIN_IN (empty by default) */
2398 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2399/* Unselect Front Mic by default in input mixer 3 */
2400 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2401/* Enable unsolicited event for HP jack */
2402 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2403/* Connect Internal Front to Front */
2404 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2405 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2406 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2407/* Connect Internal Rear to Rear */
2408 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2409 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2410 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2411/* Connect Internal CLFE to CLFE */
2412 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2413 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2414 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2415/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002416 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002417 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2418 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2419/* Enable all DACs */
2420/* DAC DISABLE/MUTE 1? */
2421/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2422 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2423 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2424/* DAC DISABLE/MUTE 2? */
2425/* some bit here disables the other DACs. Init=0x4900 */
2426 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2427 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002428/* DMIC fix
2429 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2430 * which makes the stereo useless. However, either the mic or the ALC889
2431 * makes the signal become a difference/sum signal instead of standard
2432 * stereo, which is annoying. So instead we flip this bit which makes the
2433 * codec replicate the sum signal to both channels, turning it into a
2434 * normal mono mic.
2435 */
2436/* DMIC_CONTROL? Init value = 0x0001 */
2437 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2438 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002439 { }
2440};
2441
Takashi Iwaia9111322011-05-02 11:30:18 +02002442static const struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002443 /* Front mic only available on one ADC */
2444 {
2445 .num_items = 4,
2446 .items = {
2447 { "Mic", 0x0 },
2448 { "Line", 0x2 },
2449 { "CD", 0x4 },
2450 { "Front Mic", 0xb },
2451 },
2452 },
2453 {
2454 .num_items = 3,
2455 .items = {
2456 { "Mic", 0x0 },
2457 { "Line", 0x2 },
2458 { "CD", 0x4 },
2459 },
2460 }
2461};
2462
Takashi Iwaia9111322011-05-02 11:30:18 +02002463static const struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01002464 /* Interal mic only available on one ADC */
2465 {
Tony Vroon684a8842009-06-26 09:27:50 +01002466 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002467 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002468 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002469 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002470 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002471 { "Input Mix", 0xa },
David Henningsson28c4edb2010-12-20 14:24:29 +01002472 { "Internal Mic", 0xb },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002473 },
2474 },
2475 {
Tony Vroon684a8842009-06-26 09:27:50 +01002476 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002477 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002478 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002479 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002480 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002481 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002482 },
2483 }
2484};
2485
Takashi Iwaia9111322011-05-02 11:30:18 +02002486static const struct hda_input_mux alc889_capture_sources[3] = {
Hector Martin018df412009-06-04 00:13:40 +02002487 /* Digital mic only available on first "ADC" */
2488 {
2489 .num_items = 5,
2490 .items = {
2491 { "Mic", 0x0 },
2492 { "Line", 0x2 },
2493 { "CD", 0x4 },
2494 { "Front Mic", 0xb },
2495 { "Input Mix", 0xa },
2496 },
2497 },
2498 {
2499 .num_items = 4,
2500 .items = {
2501 { "Mic", 0x0 },
2502 { "Line", 0x2 },
2503 { "CD", 0x4 },
2504 { "Input Mix", 0xa },
2505 },
2506 },
2507 {
2508 .num_items = 4,
2509 .items = {
2510 { "Mic", 0x0 },
2511 { "Line", 0x2 },
2512 { "CD", 0x4 },
2513 { "Input Mix", 0xa },
2514 },
2515 }
2516};
2517
Takashi Iwaia9111322011-05-02 11:30:18 +02002518static const struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002519 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2520 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2521 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2522 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2523 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2524 HDA_OUTPUT),
2525 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2526 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2527 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2528 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2529 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2530 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2531 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, 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),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002536 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002537 { } /* end */
2538};
2539
Takashi Iwaia9111322011-05-02 11:30:18 +02002540static const struct snd_kcontrol_new alc888_acer_aspire_4930g_mixer[] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002541 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2542 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2543 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2544 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002545 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002546 HDA_OUTPUT),
Łukasz Wojniłowicz786c51f2011-02-24 10:03:31 +01002547 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2548 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2549 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2550 HDA_CODEC_VOLUME_MONO("Internal LFE Playback Volume", 0x0f, 1, 0x0, HDA_OUTPUT),
2551 HDA_BIND_MUTE_MONO("Internal LFE Playback Switch", 0x0f, 1, 2, HDA_INPUT),
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +01002552 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2553 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2554 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2555 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2556 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2557 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
2558 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2559 { } /* end */
2560};
2561
Takashi Iwaia9111322011-05-02 11:30:18 +02002562static const struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
Hector Martin556eea92009-12-20 22:51:23 +01002563 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2564 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2565 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2566 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2567 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2568 HDA_OUTPUT),
2569 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2570 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2571 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2572 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2573 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2574 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002575 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002576 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2577 { } /* end */
2578};
2579
2580
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002581static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002582{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002583 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002584
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002585 spec->autocfg.hp_pins[0] = 0x15;
2586 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002587 spec->autocfg.speaker_pins[1] = 0x16;
2588 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002589 spec->automute = 1;
2590 spec->automute_mode = ALC_AUTOMUTE_AMP;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002591}
2592
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002593static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002594{
2595 struct alc_spec *spec = codec->spec;
2596
2597 spec->autocfg.hp_pins[0] = 0x15;
2598 spec->autocfg.speaker_pins[0] = 0x14;
2599 spec->autocfg.speaker_pins[1] = 0x16;
2600 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002601 spec->automute = 1;
2602 spec->automute_mode = ALC_AUTOMUTE_AMP;
Emilio López320d5922009-06-25 08:18:44 +02002603}
2604
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002605static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2606{
2607 struct alc_spec *spec = codec->spec;
2608
2609 spec->autocfg.hp_pins[0] = 0x15;
2610 spec->autocfg.speaker_pins[0] = 0x14;
2611 spec->autocfg.speaker_pins[1] = 0x16;
2612 spec->autocfg.speaker_pins[2] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02002613 spec->automute = 1;
2614 spec->automute_mode = ALC_AUTOMUTE_AMP;
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002615}
2616
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002617static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002618{
2619 struct alc_spec *spec = codec->spec;
2620
2621 spec->autocfg.hp_pins[0] = 0x15;
2622 spec->autocfg.speaker_pins[0] = 0x14;
2623 spec->autocfg.speaker_pins[1] = 0x16;
2624 spec->autocfg.speaker_pins[2] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02002625 spec->automute = 1;
2626 spec->automute_mode = ALC_AUTOMUTE_AMP;
Hector Martin3b315d72009-06-02 10:54:19 +02002627}
2628
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002629/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002630 * ALC880 3-stack model
2631 *
2632 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002633 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2634 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 */
2636
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002637static const hda_nid_t alc880_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002638 /* front, rear, clfe, rear_surr */
2639 0x02, 0x05, 0x04, 0x03
2640};
2641
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002642static const hda_nid_t alc880_adc_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002643 /* ADC0-2 */
2644 0x07, 0x08, 0x09,
2645};
2646
2647/* The datasheet says the node 0x07 is connected from inputs,
2648 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002649 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002651static const hda_nid_t alc880_adc_nids_alt[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002652 /* ADC1-2 */
2653 0x08, 0x09,
2654};
2655
2656#define ALC880_DIGOUT_NID 0x06
2657#define ALC880_DIGIN_NID 0x0a
2658
Takashi Iwaia9111322011-05-02 11:30:18 +02002659static const struct hda_input_mux alc880_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002660 .num_items = 4,
2661 .items = {
2662 { "Mic", 0x0 },
2663 { "Front Mic", 0x3 },
2664 { "Line", 0x2 },
2665 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002667};
2668
2669/* channel source setting (2/6 channel selection for 3-stack) */
2670/* 2ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002671static const struct hda_verb alc880_threestack_ch2_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002672 /* set line-in to input, mute it */
2673 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2674 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2675 /* set mic-in to input vref 80%, mute it */
2676 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2677 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 { } /* end */
2679};
2680
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002681/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002682static const struct hda_verb alc880_threestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002683 /* set line-in to output, unmute it */
2684 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2685 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2686 /* set mic-in to output, unmute it */
2687 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2688 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2689 { } /* end */
2690};
2691
Takashi Iwaia9111322011-05-02 11:30:18 +02002692static const struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002693 { 2, alc880_threestack_ch2_init },
2694 { 6, alc880_threestack_ch6_init },
2695};
2696
Takashi Iwaia9111322011-05-02 11:30:18 +02002697static const struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002698 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002699 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002700 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002701 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002702 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2703 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002704 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2705 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2707 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2708 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2709 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2710 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2711 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2712 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2713 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002715 {
2716 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2717 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002718 .info = alc_ch_mode_info,
2719 .get = alc_ch_mode_get,
2720 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002721 },
2722 { } /* end */
2723};
2724
2725/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002726static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2727 struct snd_ctl_elem_info *uinfo)
2728{
2729 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2730 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002731 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002732 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002733
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002734 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002735 if (spec->vol_in_capsrc)
2736 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
2737 else
2738 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
2739 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002740 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002741 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002742 return err;
2743}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002745static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2746 unsigned int size, unsigned int __user *tlv)
2747{
2748 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2749 struct alc_spec *spec = codec->spec;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002750 unsigned long val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002751 int err;
2752
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002753 mutex_lock(&codec->control_mutex);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002754 if (spec->vol_in_capsrc)
2755 val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
2756 else
2757 val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
2758 kcontrol->private_value = val;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002759 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002760 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002761 return err;
2762}
2763
2764typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2765 struct snd_ctl_elem_value *ucontrol);
2766
2767static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2768 struct snd_ctl_elem_value *ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002769 getput_call_t func, bool check_adc_switch)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002770{
2771 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2772 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02002773 int i, err = 0;
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002774
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002775 mutex_lock(&codec->control_mutex);
Takashi Iwai21268962011-07-07 15:01:13 +02002776 if (check_adc_switch && spec->dyn_adc_switch) {
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002777 for (i = 0; i < spec->num_adc_nids; i++) {
2778 kcontrol->private_value =
2779 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2780 3, 0, HDA_INPUT);
2781 err = func(kcontrol, ucontrol);
2782 if (err < 0)
2783 goto error;
2784 }
2785 } else {
2786 i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02002787 if (spec->vol_in_capsrc)
2788 kcontrol->private_value =
2789 HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i],
2790 3, 0, HDA_OUTPUT);
2791 else
2792 kcontrol->private_value =
Takashi Iwai21268962011-07-07 15:01:13 +02002793 HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
2794 3, 0, HDA_INPUT);
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002795 err = func(kcontrol, ucontrol);
2796 }
2797 error:
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002798 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002799 return err;
2800}
2801
2802static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2803 struct snd_ctl_elem_value *ucontrol)
2804{
2805 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002806 snd_hda_mixer_amp_volume_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002807}
2808
2809static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2810 struct snd_ctl_elem_value *ucontrol)
2811{
2812 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002813 snd_hda_mixer_amp_volume_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002814}
2815
2816/* capture mixer elements */
2817#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2818
2819static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2820 struct snd_ctl_elem_value *ucontrol)
2821{
2822 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002823 snd_hda_mixer_amp_switch_get, false);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002824}
2825
2826static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2827 struct snd_ctl_elem_value *ucontrol)
2828{
2829 return alc_cap_getput_caller(kcontrol, ucontrol,
Takashi Iwai9c7a0832011-07-07 09:25:54 +02002830 snd_hda_mixer_amp_switch_put, true);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002831}
2832
Takashi Iwaia23b6882009-03-23 15:21:36 +01002833#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002834 { \
2835 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2836 .name = "Capture Switch", \
2837 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2838 .count = num, \
2839 .info = alc_cap_sw_info, \
2840 .get = alc_cap_sw_get, \
2841 .put = alc_cap_sw_put, \
2842 }, \
2843 { \
2844 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2845 .name = "Capture Volume", \
2846 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2847 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2848 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2849 .count = num, \
2850 .info = alc_cap_vol_info, \
2851 .get = alc_cap_vol_get, \
2852 .put = alc_cap_vol_put, \
2853 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002854 }
2855
2856#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002857 { \
2858 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2859 /* .name = "Capture Source", */ \
2860 .name = "Input Source", \
2861 .count = num, \
2862 .info = alc_mux_enum_info, \
2863 .get = alc_mux_enum_get, \
2864 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002865 }
2866
2867#define DEFINE_CAPMIX(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002868static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002869 _DEFINE_CAPMIX(num), \
2870 _DEFINE_CAPSRC(num), \
2871 { } /* end */ \
2872}
2873
2874#define DEFINE_CAPMIX_NOSRC(num) \
Takashi Iwaia9111322011-05-02 11:30:18 +02002875static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002876 _DEFINE_CAPMIX(num), \
2877 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002878}
2879
2880/* up to three ADCs */
2881DEFINE_CAPMIX(1);
2882DEFINE_CAPMIX(2);
2883DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002884DEFINE_CAPMIX_NOSRC(1);
2885DEFINE_CAPMIX_NOSRC(2);
2886DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002887
2888/*
2889 * ALC880 5-stack model
2890 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002891 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2892 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002893 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2894 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2895 */
2896
2897/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02002898static const struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002899 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002900 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 { } /* end */
2902};
2903
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002904/* channel source setting (6/8 channel selection for 5-stack) */
2905/* 6ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002906static const struct hda_verb alc880_fivestack_ch6_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002907 /* set line-in to input, mute it */
2908 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2909 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002910 { } /* end */
2911};
2912
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002913/* 8ch mode */
Takashi Iwaia9111322011-05-02 11:30:18 +02002914static const struct hda_verb alc880_fivestack_ch8_init[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002915 /* set line-in to output, unmute it */
2916 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2917 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2918 { } /* end */
2919};
2920
Takashi Iwaia9111322011-05-02 11:30:18 +02002921static const struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002922 { 6, alc880_fivestack_ch6_init },
2923 { 8, alc880_fivestack_ch8_init },
2924};
2925
2926
2927/*
2928 * ALC880 6-stack model
2929 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002930 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2931 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002932 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2933 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2934 */
2935
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02002936static const hda_nid_t alc880_6st_dac_nids[4] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002937 /* front, rear, clfe, rear_surr */
2938 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002939};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002940
Takashi Iwaia9111322011-05-02 11:30:18 +02002941static const struct hda_input_mux alc880_6stack_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002942 .num_items = 4,
2943 .items = {
2944 { "Mic", 0x0 },
2945 { "Front Mic", 0x1 },
2946 { "Line", 0x2 },
2947 { "CD", 0x4 },
2948 },
2949};
2950
2951/* fixed 8-channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02002952static const struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002953 { 8, NULL },
2954};
2955
Takashi Iwaia9111322011-05-02 11:30:18 +02002956static const struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002957 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002958 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002959 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002960 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002961 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2962 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002963 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2964 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002965 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002966 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002967 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2968 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2969 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2970 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2971 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2972 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2973 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2974 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002975 {
2976 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2977 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002978 .info = alc_ch_mode_info,
2979 .get = alc_ch_mode_get,
2980 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002981 },
2982 { } /* end */
2983};
2984
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002985
2986/*
2987 * ALC880 W810 model
2988 *
2989 * W810 has rear IO for:
2990 * Front (DAC 02)
2991 * Surround (DAC 03)
2992 * Center/LFE (DAC 04)
2993 * Digital out (06)
2994 *
2995 * The system also has a pair of internal speakers, and a headphone jack.
2996 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002997 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002998 * There is a variable resistor to control the speaker or headphone
2999 * volume. This is a hardware-only device without a software API.
3000 *
3001 * Plugging headphones in will disable the internal speakers. This is
3002 * implemented in hardware, not via the driver using jack sense. In
3003 * a similar fashion, plugging into the rear socket marked "front" will
3004 * disable both the speakers and headphones.
3005 *
3006 * For input, there's a microphone jack, and an "audio in" jack.
3007 * These may not do anything useful with this driver yet, because I
3008 * haven't setup any initialization verbs for these yet...
3009 */
3010
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003011static const hda_nid_t alc880_w810_dac_nids[3] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003012 /* front, rear/surround, clfe */
3013 0x02, 0x03, 0x04
3014};
3015
3016/* fixed 6 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02003017static const struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003018 { 6, NULL }
3019};
3020
3021/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaia9111322011-05-02 11:30:18 +02003022static const struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003023 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003024 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003025 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003026 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003027 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3028 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003029 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3030 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003031 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3032 { } /* end */
3033};
3034
3035
3036/*
3037 * Z710V model
3038 *
3039 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003040 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
3041 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003042 */
3043
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003044static const hda_nid_t alc880_z71v_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003045 0x02
3046};
3047#define ALC880_Z71V_HP_DAC 0x03
3048
3049/* fixed 2 channels */
Takashi Iwaia9111322011-05-02 11:30:18 +02003050static const struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003051 { 2, NULL }
3052};
3053
Takashi Iwaia9111322011-05-02 11:30:18 +02003054static const struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003055 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003056 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003057 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003058 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003059 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3060 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3061 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3062 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3063 { } /* end */
3064};
3065
3066
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003067/*
3068 * ALC880 F1734 model
3069 *
3070 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
3071 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
3072 */
3073
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003074static const hda_nid_t alc880_f1734_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003075 0x03
3076};
3077#define ALC880_F1734_HP_DAC 0x02
3078
Takashi Iwaia9111322011-05-02 11:30:18 +02003079static const struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003080 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003081 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01003082 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3083 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003084 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3085 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01003086 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3087 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003088 { } /* end */
3089};
3090
Takashi Iwaia9111322011-05-02 11:30:18 +02003091static const struct hda_input_mux alc880_f1734_capture_source = {
Takashi Iwai937b4162008-02-11 14:52:36 +01003092 .num_items = 2,
3093 .items = {
3094 { "Mic", 0x1 },
3095 { "CD", 0x4 },
3096 },
3097};
3098
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003099
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003100/*
3101 * ALC880 ASUS model
3102 *
3103 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3104 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3105 * Mic = 0x18, Line = 0x1a
3106 */
3107
3108#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
3109#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
3110
Takashi Iwaia9111322011-05-02 11:30:18 +02003111static const struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003112 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003113 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003114 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003115 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003116 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3117 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01003118 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3119 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003120 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3121 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3122 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3123 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3124 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3125 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003126 {
3127 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3128 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01003129 .info = alc_ch_mode_info,
3130 .get = alc_ch_mode_get,
3131 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02003132 },
3133 { } /* end */
3134};
3135
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003136/*
3137 * ALC880 ASUS W1V model
3138 *
3139 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
3140 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
3141 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
3142 */
3143
3144/* additional mixers to alc880_asus_mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +02003145static const struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02003146 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
3147 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02003148 { } /* end */
3149};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003150
Kailang Yangdf694da2005-12-05 19:42:22 +01003151/* TCL S700 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003152static const struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003153 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3154 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
3155 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
3156 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
3157 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
3158 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
3159 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
3160 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
3161 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01003162 { } /* end */
3163};
3164
Kailang Yangccc656c2006-10-17 12:32:26 +02003165/* Uniwill */
Takashi Iwaia9111322011-05-02 11:30:18 +02003166static const struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003167 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3168 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3169 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3170 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003171 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3172 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3173 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3174 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3175 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3176 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
3177 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3178 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
3179 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3180 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3181 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3182 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003183 {
3184 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3185 .name = "Channel Mode",
3186 .info = alc_ch_mode_info,
3187 .get = alc_ch_mode_get,
3188 .put = alc_ch_mode_put,
3189 },
3190 { } /* end */
3191};
3192
Takashi Iwaia9111322011-05-02 11:30:18 +02003193static const struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003194 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3195 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3196 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3197 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
3198 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
3199 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01003200 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3201 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01003202 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3203 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003204 { } /* end */
3205};
3206
Takashi Iwaia9111322011-05-02 11:30:18 +02003207static const struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003208 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3209 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
3210 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
3211 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02003212 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3213 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3214 { } /* end */
3215};
3216
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01003218 * virtual master controls
3219 */
3220
3221/*
3222 * slave controls for virtual master
3223 */
Takashi Iwaiea734962011-01-17 11:29:34 +01003224static const char * const alc_slave_vols[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003225 "Front Playback Volume",
3226 "Surround Playback Volume",
3227 "Center Playback Volume",
3228 "LFE Playback Volume",
3229 "Side Playback Volume",
3230 "Headphone Playback Volume",
3231 "Speaker Playback Volume",
3232 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003233 "Line-Out Playback Volume",
3234 NULL,
3235};
3236
Takashi Iwaiea734962011-01-17 11:29:34 +01003237static const char * const alc_slave_sws[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003238 "Front Playback Switch",
3239 "Surround Playback Switch",
3240 "Center Playback Switch",
3241 "LFE Playback Switch",
3242 "Side Playback Switch",
3243 "Headphone Playback Switch",
3244 "Speaker Playback Switch",
3245 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01003246 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01003247 "Line-Out Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003248 NULL,
3249};
3250
3251/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003252 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 */
Takashi Iwai603c4012008-07-30 15:01:44 +02003254
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003255#define NID_MAPPING (-1)
3256
3257#define SUBDEV_SPEAKER_ (0 << 6)
3258#define SUBDEV_HP_ (1 << 6)
3259#define SUBDEV_LINE_ (2 << 6)
3260#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
3261#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
3262#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
3263
Takashi Iwai603c4012008-07-30 15:01:44 +02003264static void alc_free_kctls(struct hda_codec *codec);
3265
Takashi Iwai67d634c2009-11-16 15:35:59 +01003266#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003267/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwaia9111322011-05-02 11:30:18 +02003268static const struct snd_kcontrol_new alc_beep_mixer[] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003269 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02003270 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003271 { } /* end */
3272};
Takashi Iwai67d634c2009-11-16 15:35:59 +01003273#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275static int alc_build_controls(struct hda_codec *codec)
3276{
3277 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02003278 struct snd_kcontrol *kctl = NULL;
Takashi Iwaia9111322011-05-02 11:30:18 +02003279 const struct snd_kcontrol_new *knew;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003280 int i, j, err;
3281 unsigned int u;
3282 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
3284 for (i = 0; i < spec->num_mixers; i++) {
3285 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
3286 if (err < 0)
3287 return err;
3288 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01003289 if (spec->cap_mixer) {
3290 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
3291 if (err < 0)
3292 return err;
3293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003295 err = snd_hda_create_spdif_out_ctls(codec,
Stephen Warren74b654c2011-06-01 11:14:18 -06003296 spec->multiout.dig_out_nid,
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003297 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 if (err < 0)
3299 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003300 if (!spec->no_analog) {
3301 err = snd_hda_create_spdif_share_sw(codec,
3302 &spec->multiout);
3303 if (err < 0)
3304 return err;
3305 spec->multiout.share_spdif = 1;
3306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 }
3308 if (spec->dig_in_nid) {
3309 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
3310 if (err < 0)
3311 return err;
3312 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01003313
Takashi Iwai67d634c2009-11-16 15:35:59 +01003314#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003315 /* create beep controls if needed */
3316 if (spec->beep_amp) {
Takashi Iwaia9111322011-05-02 11:30:18 +02003317 const struct snd_kcontrol_new *knew;
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003318 for (knew = alc_beep_mixer; knew->name; knew++) {
3319 struct snd_kcontrol *kctl;
3320 kctl = snd_ctl_new1(knew, codec);
3321 if (!kctl)
3322 return -ENOMEM;
3323 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01003324 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003325 if (err < 0)
3326 return err;
3327 }
3328 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01003329#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01003330
Takashi Iwai2134ea42008-01-10 16:53:55 +01003331 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003332 if (!spec->no_analog &&
3333 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003334 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01003335 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003336 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003337 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01003338 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01003339 if (err < 0)
3340 return err;
3341 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01003342 if (!spec->no_analog &&
3343 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003344 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
3345 NULL, alc_slave_sws);
3346 if (err < 0)
3347 return err;
3348 }
3349
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003350 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003351 if (spec->capsrc_nids || spec->adc_nids) {
3352 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
3353 if (!kctl)
3354 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3355 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003356 const hda_nid_t *nids = spec->capsrc_nids;
Takashi Iwaifbe618f2010-06-11 11:24:58 +02003357 if (!nids)
3358 nids = spec->adc_nids;
3359 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3360 if (err < 0)
3361 return err;
3362 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003363 }
3364 if (spec->cap_mixer) {
3365 const char *kname = kctl ? kctl->id.name : NULL;
3366 for (knew = spec->cap_mixer; knew->name; knew++) {
3367 if (kname && strcmp(knew->name, kname) == 0)
3368 continue;
3369 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3370 for (i = 0; kctl && i < kctl->count; i++) {
3371 err = snd_hda_add_nid(codec, kctl, i,
3372 spec->adc_nids[i]);
3373 if (err < 0)
3374 return err;
3375 }
3376 }
3377 }
3378
3379 /* other nid->control mapping */
3380 for (i = 0; i < spec->num_mixers; i++) {
3381 for (knew = spec->mixers[i]; knew->name; knew++) {
3382 if (knew->iface != NID_MAPPING)
3383 continue;
3384 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3385 if (kctl == NULL)
3386 continue;
3387 u = knew->subdevice;
3388 for (j = 0; j < 4; j++, u >>= 8) {
3389 nid = u & 0x3f;
3390 if (nid == 0)
3391 continue;
3392 switch (u & 0xc0) {
3393 case SUBDEV_SPEAKER_:
3394 nid = spec->autocfg.speaker_pins[nid];
3395 break;
3396 case SUBDEV_LINE_:
3397 nid = spec->autocfg.line_out_pins[nid];
3398 break;
3399 case SUBDEV_HP_:
3400 nid = spec->autocfg.hp_pins[nid];
3401 break;
3402 default:
3403 continue;
3404 }
3405 err = snd_hda_add_nid(codec, kctl, 0, nid);
3406 if (err < 0)
3407 return err;
3408 }
3409 u = knew->private_value;
3410 for (j = 0; j < 4; j++, u >>= 8) {
3411 nid = u & 0xff;
3412 if (nid == 0)
3413 continue;
3414 err = snd_hda_add_nid(codec, kctl, 0, nid);
3415 if (err < 0)
3416 return err;
3417 }
3418 }
3419 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003420
3421 alc_free_kctls(codec); /* no longer needed */
3422
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 return 0;
3424}
3425
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003426
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427/*
3428 * initialize the codec volumes, etc
3429 */
3430
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003431/*
3432 * generic initialization of ADC, input mixers and output mixers
3433 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003434static const struct hda_verb alc880_volume_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003435 /*
3436 * Unmute ADC0-2 and set the default input to mic-in
3437 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003438 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003439 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003440 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003441 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003442 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003443 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003445 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3446 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003447 * Note: PASD motherboards uses the Line In 2 as the input for front
3448 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003450 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003451 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3452 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3453 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3454 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3455 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3456 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3457 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003459 /*
3460 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003462 /* set vol=0 to output mixers */
3463 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3464 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3465 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3466 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3467 /* set up input amps for analog loopback */
3468 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003469 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3470 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003471 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3472 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003473 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3474 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003475 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3476 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
3478 { }
3479};
3480
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003481/*
3482 * 3-stack pin configuration:
3483 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3484 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003485static const struct hda_verb alc880_pin_3stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003486 /*
3487 * preset connection lists of input pins
3488 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3489 */
3490 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3491 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3492 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3493
3494 /*
3495 * Set pin mode and muting
3496 */
3497 /* set front pin widgets 0x14 for output */
3498 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3499 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3500 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3501 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3502 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3503 /* Mic2 (as headphone out) for HP output */
3504 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3505 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3506 /* Line In pin widget for input */
3507 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3508 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3509 /* Line2 (as front mic) pin widget for input and vref at 80% */
3510 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3511 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3512 /* CD pin widget for input */
3513 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3514
3515 { }
3516};
3517
3518/*
3519 * 5-stack pin configuration:
3520 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3521 * line-in/side = 0x1a, f-mic = 0x1b
3522 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003523static const struct hda_verb alc880_pin_5stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003524 /*
3525 * preset connection lists of input pins
3526 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3527 */
3528 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3529 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3530
3531 /*
3532 * Set pin mode and muting
3533 */
3534 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003535 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3536 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3537 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3538 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003539 /* unmute pins for output (no gain on this amp) */
3540 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3541 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3542 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3543 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3544
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003546 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003547 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3548 /* Mic2 (as headphone out) for HP output */
3549 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003550 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003551 /* Line In pin widget for input */
3552 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3553 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3554 /* Line2 (as front mic) pin widget for input and vref at 80% */
3555 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3556 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3557 /* CD pin widget for input */
3558 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559
3560 { }
3561};
3562
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003563/*
3564 * W810 pin configuration:
3565 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3566 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003567static const struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 /* hphone/speaker input selector: front DAC */
3569 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3570
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003571 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3572 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3573 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3574 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3575 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3576 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3577
3578 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003579 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 { }
3582};
3583
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003584/*
3585 * Z71V pin configuration:
3586 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3587 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003588static const struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003589 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003590 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003591 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003592 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003593
Takashi Iwai16ded522005-06-10 19:58:24 +02003594 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003595 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003596 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003597 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003598
3599 { }
3600};
3601
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003602/*
3603 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003604 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3605 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003606 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003607static const struct hda_verb alc880_pin_6stack_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003608 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3609
Takashi Iwai16ded522005-06-10 19:58:24 +02003610 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003611 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003612 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003613 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003614 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003615 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003616 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003617 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3618
Takashi Iwai16ded522005-06-10 19:58:24 +02003619 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003620 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003621 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003622 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003623 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003624 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003625 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003626 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003627 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003628
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003629 { }
3630};
Takashi Iwai16ded522005-06-10 19:58:24 +02003631
Kailang Yangccc656c2006-10-17 12:32:26 +02003632/*
3633 * Uniwill pin configuration:
3634 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3635 * line = 0x1a
3636 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003637static const struct hda_verb alc880_uniwill_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003638 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3639
3640 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3641 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3642 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3643 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3644 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3645 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3646 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3647 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3648 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3649 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3650 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3651 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3652 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3653 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3654
3655 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3656 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3657 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3658 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3659 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3660 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3661 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3662 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3663 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3664
3665 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3666 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3667
3668 { }
3669};
3670
3671/*
3672* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003673* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003674 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003675static const struct hda_verb alc880_uniwill_p53_init_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02003676 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3677
3678 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3679 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3680 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3681 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3682 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3683 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3684 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3685 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3686 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3687 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3688 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3689 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3690
3691 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3692 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3693 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3694 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3695 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3696 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3697
3698 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3699 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3700
3701 { }
3702};
3703
Takashi Iwaia9111322011-05-02 11:30:18 +02003704static const struct hda_verb alc880_beep_init_verbs[] = {
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003705 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3706 { }
3707};
3708
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003709/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003710static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003711{
3712 unsigned int present;
3713 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003714
Wu Fengguang864f92b2009-11-18 12:38:02 +08003715 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003716 bits = present ? HDA_AMP_MUTE : 0;
3717 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003718}
3719
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003720static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003721{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003722 struct alc_spec *spec = codec->spec;
3723
3724 spec->autocfg.hp_pins[0] = 0x14;
3725 spec->autocfg.speaker_pins[0] = 0x15;
3726 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02003727 spec->automute = 1;
3728 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003729}
3730
3731static void alc880_uniwill_init_hook(struct hda_codec *codec)
3732{
Takashi Iwaid922b512011-04-28 12:18:53 +02003733 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003734 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003735}
3736
3737static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3738 unsigned int res)
3739{
3740 /* Looks like the unsol event is incompatible with the standard
3741 * definition. 4bit tag is placed at 28 bit!
3742 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003743 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003744 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003745 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003746 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003747 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02003748 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003749 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003750 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003751}
3752
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003753static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003754{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003755 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003756
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003757 spec->autocfg.hp_pins[0] = 0x14;
3758 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02003759 spec->automute = 1;
3760 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangccc656c2006-10-17 12:32:26 +02003761}
3762
3763static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3764{
3765 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003766
Kailang Yangccc656c2006-10-17 12:32:26 +02003767 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003768 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3769 present &= HDA_AMP_VOLMASK;
3770 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3771 HDA_AMP_VOLMASK, present);
3772 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3773 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003774}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003775
Kailang Yangccc656c2006-10-17 12:32:26 +02003776static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3777 unsigned int res)
3778{
3779 /* Looks like the unsol event is incompatible with the standard
3780 * definition. 4bit tag is placed at 28 bit!
3781 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003782 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003783 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003784 else
Takashi Iwaid922b512011-04-28 12:18:53 +02003785 alc_sku_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003786}
3787
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003788/*
3789 * F1734 pin configuration:
3790 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3791 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003792static const struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003793 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003794 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3795 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3796 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3797 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3798
3799 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3800 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3801 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3802 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3803
3804 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3805 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003806 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003807 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3808 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3809 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3810 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3811 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3812 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003813
Takashi Iwai937b4162008-02-11 14:52:36 +01003814 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3815 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3816
Takashi Iwai16ded522005-06-10 19:58:24 +02003817 { }
3818};
3819
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003820/*
3821 * ASUS pin configuration:
3822 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3823 */
Takashi Iwaia9111322011-05-02 11:30:18 +02003824static const struct hda_verb alc880_pin_asus_init_verbs[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003825 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3826 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3827 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3828 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3829
3830 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3831 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3832 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3833 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3834 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3835 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3836 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3837 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3838
3839 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3840 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3841 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3842 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3843 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3844 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3845 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3846 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3847 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003848
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003849 { }
3850};
3851
3852/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003853#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3854#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003855#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003856
Kailang Yangdf694da2005-12-05 19:42:22 +01003857/* Clevo m520g init */
Takashi Iwaia9111322011-05-02 11:30:18 +02003858static const struct hda_verb alc880_pin_clevo_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01003859 /* headphone output */
3860 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3861 /* line-out */
3862 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3863 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3864 /* Line-in */
3865 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3866 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3867 /* CD */
3868 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3869 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3870 /* Mic1 (rear panel) */
3871 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3872 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3873 /* Mic2 (front panel) */
3874 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3875 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3876 /* headphone */
3877 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3878 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3879 /* change to EAPD mode */
3880 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3881 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3882
3883 { }
3884};
3885
Takashi Iwaia9111322011-05-02 11:30:18 +02003886static const struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003887 /* change to EAPD mode */
3888 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3889 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3890
Kailang Yangdf694da2005-12-05 19:42:22 +01003891 /* Headphone output */
3892 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3893 /* Front output*/
3894 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3895 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3896
3897 /* Line In pin widget for input */
3898 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3899 /* CD pin widget for input */
3900 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3901 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3902 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3903
3904 /* change to EAPD mode */
3905 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3906 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3907
3908 { }
3909};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003910
3911/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003912 * LG m1 express dual
3913 *
3914 * Pin assignment:
3915 * Rear Line-In/Out (blue): 0x14
3916 * Build-in Mic-In: 0x15
3917 * Speaker-out: 0x17
3918 * HP-Out (green): 0x1b
3919 * Mic-In/Out (red): 0x19
3920 * SPDIF-Out: 0x1e
3921 */
3922
3923/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02003924static const hda_nid_t alc880_lg_dac_nids[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003925 0x05, 0x02, 0x03
3926};
3927
3928/* seems analog CD is not working */
Takashi Iwaia9111322011-05-02 11:30:18 +02003929static const struct hda_input_mux alc880_lg_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003930 .num_items = 3,
3931 .items = {
3932 { "Mic", 0x1 },
3933 { "Line", 0x5 },
3934 { "Internal Mic", 0x6 },
3935 },
3936};
3937
3938/* 2,4,6 channel modes */
Takashi Iwaia9111322011-05-02 11:30:18 +02003939static const struct hda_verb alc880_lg_ch2_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003940 /* set line-in and mic-in to input */
3941 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3942 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3943 { }
3944};
3945
Takashi Iwaia9111322011-05-02 11:30:18 +02003946static const struct hda_verb alc880_lg_ch4_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003947 /* set line-in to out and mic-in to input */
3948 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3949 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3950 { }
3951};
3952
Takashi Iwaia9111322011-05-02 11:30:18 +02003953static const struct hda_verb alc880_lg_ch6_init[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003954 /* set line-in and mic-in to output */
3955 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3956 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3957 { }
3958};
3959
Takashi Iwaia9111322011-05-02 11:30:18 +02003960static const struct hda_channel_mode alc880_lg_ch_modes[3] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003961 { 2, alc880_lg_ch2_init },
3962 { 4, alc880_lg_ch4_init },
3963 { 6, alc880_lg_ch6_init },
3964};
3965
Takashi Iwaia9111322011-05-02 11:30:18 +02003966static const struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003967 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3968 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003969 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3970 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3971 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3972 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3973 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3974 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3975 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3976 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3977 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3978 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3979 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3980 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3981 {
3982 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3983 .name = "Channel Mode",
3984 .info = alc_ch_mode_info,
3985 .get = alc_ch_mode_get,
3986 .put = alc_ch_mode_put,
3987 },
3988 { } /* end */
3989};
3990
Takashi Iwaia9111322011-05-02 11:30:18 +02003991static const struct hda_verb alc880_lg_init_verbs[] = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003992 /* set capture source to mic-in */
3993 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3994 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3995 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3996 /* mute all amp mixer inputs */
3997 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003998 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3999 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004000 /* line-in to input */
4001 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4002 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4003 /* built-in mic */
4004 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4005 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4006 /* speaker-out */
4007 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4008 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4009 /* mic-in to input */
4010 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
4011 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4012 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4013 /* HP-out */
4014 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
4015 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4016 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4017 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004018 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004019 { }
4020};
4021
4022/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004023static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004024{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004025 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004026
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004027 spec->autocfg.hp_pins[0] = 0x1b;
4028 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02004029 spec->automute = 1;
4030 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004031}
4032
4033/*
Takashi Iwaid6815182006-03-23 16:06:23 +01004034 * LG LW20
4035 *
4036 * Pin assignment:
4037 * Speaker-out: 0x14
4038 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02004039 * Built-in Mic-In: 0x19
4040 * Line-In: 0x1b
4041 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01004042 * SPDIF-Out: 0x1e
4043 */
4044
Takashi Iwaia9111322011-05-02 11:30:18 +02004045static const struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02004046 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01004047 .items = {
4048 { "Mic", 0x0 },
4049 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02004050 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004051 },
4052};
4053
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004054#define alc880_lg_lw_modes alc880_threestack_modes
4055
Takashi Iwaia9111322011-05-02 11:30:18 +02004056static const struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004057 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4058 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4059 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
4060 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
4061 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
4062 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
4063 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
4064 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
4065 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
4066 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01004067 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4068 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4069 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
4070 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004071 {
4072 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4073 .name = "Channel Mode",
4074 .info = alc_ch_mode_info,
4075 .get = alc_ch_mode_get,
4076 .put = alc_ch_mode_put,
4077 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004078 { } /* end */
4079};
4080
Takashi Iwaia9111322011-05-02 11:30:18 +02004081static const struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004082 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4083 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
4084 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
4085
Takashi Iwaid6815182006-03-23 16:06:23 +01004086 /* set capture source to mic-in */
4087 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4088 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4089 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02004090 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01004091 /* speaker-out */
4092 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4093 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4094 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01004095 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4096 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4097 /* mic-in to input */
4098 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4099 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4100 /* built-in mic */
4101 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4102 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4103 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004104 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01004105 { }
4106};
4107
4108/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004109static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01004110{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004111 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01004112
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004113 spec->autocfg.hp_pins[0] = 0x1b;
4114 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02004115 spec->automute = 1;
4116 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaid6815182006-03-23 16:06:23 +01004117}
4118
Takashi Iwaia9111322011-05-02 11:30:18 +02004119static const struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004120 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4121 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
4122 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
4123 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
4124 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
4125 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
4126 { } /* end */
4127};
4128
Takashi Iwaia9111322011-05-02 11:30:18 +02004129static const struct hda_input_mux alc880_medion_rim_capture_source = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004130 .num_items = 2,
4131 .items = {
4132 { "Mic", 0x0 },
4133 { "Internal Mic", 0x1 },
4134 },
4135};
4136
Takashi Iwaia9111322011-05-02 11:30:18 +02004137static const struct hda_verb alc880_medion_rim_init_verbs[] = {
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004138 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
4139
4140 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4141 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4142
4143 /* Mic1 (rear panel) pin widget for input and vref at 80% */
4144 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4145 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4146 /* Mic2 (as headphone out) for HP output */
4147 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4148 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4149 /* Internal Speaker */
4150 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4151 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4152
4153 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
4154 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
4155
4156 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
4157 { }
4158};
4159
4160/* toggle speaker-output according to the hp-jack state */
4161static void alc880_medion_rim_automute(struct hda_codec *codec)
4162{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004163 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02004164 alc_hp_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004165 /* toggle EAPD */
4166 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004167 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
4168 else
4169 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
4170}
4171
4172static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
4173 unsigned int res)
4174{
4175 /* Looks like the unsol event is incompatible with the standard
4176 * definition. 4bit tag is placed at 28 bit!
4177 */
4178 if ((res >> 28) == ALC880_HP_EVENT)
4179 alc880_medion_rim_automute(codec);
4180}
4181
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004182static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004183{
4184 struct alc_spec *spec = codec->spec;
4185
4186 spec->autocfg.hp_pins[0] = 0x14;
4187 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02004188 spec->automute = 1;
4189 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004190}
4191
Takashi Iwaicb53c622007-08-10 17:21:45 +02004192#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02004193static const struct hda_amp_list alc880_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004194 { 0x0b, HDA_INPUT, 0 },
4195 { 0x0b, HDA_INPUT, 1 },
4196 { 0x0b, HDA_INPUT, 2 },
4197 { 0x0b, HDA_INPUT, 3 },
4198 { 0x0b, HDA_INPUT, 4 },
4199 { } /* end */
4200};
4201
Takashi Iwaia9111322011-05-02 11:30:18 +02004202static const struct hda_amp_list alc880_lg_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02004203 { 0x0b, HDA_INPUT, 1 },
4204 { 0x0b, HDA_INPUT, 6 },
4205 { 0x0b, HDA_INPUT, 7 },
4206 { } /* end */
4207};
4208#endif
4209
Takashi Iwaid6815182006-03-23 16:06:23 +01004210/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004211 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004212 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004213
Takashi Iwai584c0c42011-03-10 12:51:11 +01004214static void alc_init_special_input_src(struct hda_codec *codec);
4215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216static int alc_init(struct hda_codec *codec)
4217{
4218 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004219 unsigned int i;
4220
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004221 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02004222 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02004223
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004224 for (i = 0; i < spec->num_init_verbs; i++)
4225 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai584c0c42011-03-10 12:51:11 +01004226 alc_init_special_input_src(codec);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004227
4228 if (spec->init_hook)
4229 spec->init_hook(codec);
4230
Takashi Iwai58701122011-01-13 15:41:45 +01004231 alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
4232
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004233 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 return 0;
4235}
4236
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004237static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
4238{
4239 struct alc_spec *spec = codec->spec;
4240
4241 if (spec->unsol_event)
4242 spec->unsol_event(codec, res);
4243}
4244
Takashi Iwaicb53c622007-08-10 17:21:45 +02004245#ifdef CONFIG_SND_HDA_POWER_SAVE
4246static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
4247{
4248 struct alc_spec *spec = codec->spec;
4249 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
4250}
4251#endif
4252
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253/*
4254 * Analog playback callbacks
4255 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004256static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004258 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259{
4260 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01004261 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
4262 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263}
4264
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004265static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 struct hda_codec *codec,
4267 unsigned int stream_tag,
4268 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004269 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270{
4271 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004272 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
4273 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274}
4275
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004276static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004278 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279{
4280 struct alc_spec *spec = codec->spec;
4281 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
4282}
4283
4284/*
4285 * Digital out
4286 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004287static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004289 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290{
4291 struct alc_spec *spec = codec->spec;
4292 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
4293}
4294
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004295static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004296 struct hda_codec *codec,
4297 unsigned int stream_tag,
4298 unsigned int format,
4299 struct snd_pcm_substream *substream)
4300{
4301 struct alc_spec *spec = codec->spec;
4302 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
4303 stream_tag, format, substream);
4304}
4305
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004306static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004307 struct hda_codec *codec,
4308 struct snd_pcm_substream *substream)
4309{
4310 struct alc_spec *spec = codec->spec;
4311 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
4312}
4313
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004314static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004316 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317{
4318 struct alc_spec *spec = codec->spec;
4319 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
4320}
4321
4322/*
4323 * Analog capture
4324 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004325static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 struct hda_codec *codec,
4327 unsigned int stream_tag,
4328 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004329 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330{
4331 struct alc_spec *spec = codec->spec;
4332
Takashi Iwai63300792008-01-24 15:31:36 +01004333 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 stream_tag, 0, format);
4335 return 0;
4336}
4337
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004338static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004340 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341{
4342 struct alc_spec *spec = codec->spec;
4343
Takashi Iwai888afa12008-03-18 09:57:50 +01004344 snd_hda_codec_cleanup_stream(codec,
4345 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 return 0;
4347}
4348
Takashi Iwai840b64c2010-07-13 22:49:01 +02004349/* analog capture with dynamic dual-adc changes */
Takashi Iwai21268962011-07-07 15:01:13 +02004350static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02004351 struct hda_codec *codec,
4352 unsigned int stream_tag,
4353 unsigned int format,
4354 struct snd_pcm_substream *substream)
4355{
4356 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02004357 spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
Takashi Iwai840b64c2010-07-13 22:49:01 +02004358 spec->cur_adc_stream_tag = stream_tag;
4359 spec->cur_adc_format = format;
4360 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
4361 return 0;
4362}
4363
Takashi Iwai21268962011-07-07 15:01:13 +02004364static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Takashi Iwai840b64c2010-07-13 22:49:01 +02004365 struct hda_codec *codec,
4366 struct snd_pcm_substream *substream)
4367{
4368 struct alc_spec *spec = codec->spec;
4369 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4370 spec->cur_adc = 0;
4371 return 0;
4372}
4373
Takashi Iwai21268962011-07-07 15:01:13 +02004374static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
Takashi Iwai840b64c2010-07-13 22:49:01 +02004375 .substreams = 1,
4376 .channels_min = 2,
4377 .channels_max = 2,
4378 .nid = 0, /* fill later */
4379 .ops = {
Takashi Iwai21268962011-07-07 15:01:13 +02004380 .prepare = dyn_adc_capture_pcm_prepare,
4381 .cleanup = dyn_adc_capture_pcm_cleanup
Takashi Iwai840b64c2010-07-13 22:49:01 +02004382 },
4383};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384
4385/*
4386 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004387static const struct hda_pcm_stream alc_pcm_analog_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 .substreams = 1,
4389 .channels_min = 2,
4390 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004391 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004393 .open = alc_playback_pcm_open,
4394 .prepare = alc_playback_pcm_prepare,
4395 .cleanup = alc_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 },
4397};
4398
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004399static const struct hda_pcm_stream alc_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004400 .substreams = 1,
4401 .channels_min = 2,
4402 .channels_max = 2,
4403 /* NID is set in alc_build_pcms */
4404};
4405
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004406static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
Takashi Iwai63300792008-01-24 15:31:36 +01004407 .substreams = 1,
4408 .channels_min = 2,
4409 .channels_max = 2,
4410 /* NID is set in alc_build_pcms */
4411};
4412
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004413static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004414 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 .channels_min = 2,
4416 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004417 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004419 .prepare = alc_alt_capture_pcm_prepare,
4420 .cleanup = alc_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 },
4422};
4423
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004424static const struct hda_pcm_stream alc_pcm_digital_playback = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 .substreams = 1,
4426 .channels_min = 2,
4427 .channels_max = 2,
4428 /* NID is set in alc_build_pcms */
4429 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004430 .open = alc_dig_playback_pcm_open,
4431 .close = alc_dig_playback_pcm_close,
4432 .prepare = alc_dig_playback_pcm_prepare,
4433 .cleanup = alc_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 },
4435};
4436
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004437static const struct hda_pcm_stream alc_pcm_digital_capture = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 .substreams = 1,
4439 .channels_min = 2,
4440 .channels_max = 2,
4441 /* NID is set in alc_build_pcms */
4442};
4443
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004444/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwaia9111322011-05-02 11:30:18 +02004445static const struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004446 .substreams = 0,
4447 .channels_min = 0,
4448 .channels_max = 0,
4449};
4450
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451static int alc_build_pcms(struct hda_codec *codec)
4452{
4453 struct alc_spec *spec = codec->spec;
4454 struct hda_pcm *info = spec->pcm_rec;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004455 const struct hda_pcm_stream *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 int i;
4457
4458 codec->num_pcms = 1;
4459 codec->pcm_info = info;
4460
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004461 if (spec->no_analog)
4462 goto skip_analog;
4463
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004464 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4465 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004467
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004468 if (spec->multiout.dac_nids > 0) {
4469 p = spec->stream_analog_playback;
4470 if (!p)
4471 p = &alc_pcm_analog_playback;
4472 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004473 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4474 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004475 if (spec->adc_nids) {
4476 p = spec->stream_analog_capture;
Takashi Iwai21268962011-07-07 15:01:13 +02004477 if (!p) {
4478 if (spec->dyn_adc_switch)
4479 p = &dyn_adc_pcm_analog_capture;
4480 else
4481 p = &alc_pcm_analog_capture;
4482 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004483 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004484 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486
Takashi Iwai4a471b72005-12-07 13:56:29 +01004487 if (spec->channel_mode) {
4488 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4489 for (i = 0; i < spec->num_channel_mode; i++) {
4490 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4491 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 }
4494 }
4495
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004496 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004497 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004499 snprintf(spec->stream_name_digital,
4500 sizeof(spec->stream_name_digital),
4501 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004502 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004503 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004504 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004506 if (spec->dig_out_type)
4507 info->pcm_type = spec->dig_out_type;
4508 else
4509 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004510 if (spec->multiout.dig_out_nid) {
4511 p = spec->stream_digital_playback;
4512 if (!p)
4513 p = &alc_pcm_digital_playback;
4514 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4516 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004517 if (spec->dig_in_nid) {
4518 p = spec->stream_digital_capture;
4519 if (!p)
4520 p = &alc_pcm_digital_capture;
4521 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4523 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004524 /* FIXME: do we need this for all Realtek codec models? */
4525 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 }
4527
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004528 if (spec->no_analog)
4529 return 0;
4530
Takashi Iwaie08a0072006-09-07 17:52:14 +02004531 /* If the use of more than one ADC is requested for the current
4532 * model, configure a second analog capture-only PCM.
4533 */
4534 /* Additional Analaog capture for index #2 */
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004535 if (spec->alt_dac_nid || spec->num_adc_nids > 1) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004536 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004537 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004538 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004539 if (spec->alt_dac_nid) {
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004540 p = spec->stream_analog_alt_playback;
4541 if (!p)
4542 p = &alc_pcm_analog_alt_playback;
4543 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01004544 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4545 spec->alt_dac_nid;
4546 } else {
4547 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4548 alc_pcm_null_stream;
4549 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4550 }
Takashi Iwaic2d986b2011-07-06 18:30:08 +02004551 if (spec->num_adc_nids > 1) {
4552 p = spec->stream_analog_alt_capture;
4553 if (!p)
4554 p = &alc_pcm_analog_alt_capture;
4555 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
Takashi Iwai63300792008-01-24 15:31:36 +01004556 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4557 spec->adc_nids[1];
4558 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4559 spec->num_adc_nids - 1;
4560 } else {
4561 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4562 alc_pcm_null_stream;
4563 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004564 }
4565 }
4566
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 return 0;
4568}
4569
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004570static inline void alc_shutup(struct hda_codec *codec)
4571{
Takashi Iwai1c716152011-04-07 10:37:16 +02004572 struct alc_spec *spec = codec->spec;
4573
4574 if (spec && spec->shutup)
4575 spec->shutup(codec);
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004576 snd_hda_shutup_pins(codec);
4577}
4578
Takashi Iwai603c4012008-07-30 15:01:44 +02004579static void alc_free_kctls(struct hda_codec *codec)
4580{
4581 struct alc_spec *spec = codec->spec;
4582
4583 if (spec->kctls.list) {
4584 struct snd_kcontrol_new *kctl = spec->kctls.list;
4585 int i;
4586 for (i = 0; i < spec->kctls.used; i++)
4587 kfree(kctl[i].name);
4588 }
4589 snd_array_free(&spec->kctls);
4590}
4591
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592static void alc_free(struct hda_codec *codec)
4593{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004594 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004595
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004596 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004597 return;
4598
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004599 alc_shutup(codec);
Takashi Iwaicd372fb2011-03-03 14:40:14 +01004600 snd_hda_input_jack_free(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004601 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004602 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004603 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604}
4605
Hector Martinf5de24b2009-12-20 22:51:31 +01004606#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004607static void alc_power_eapd(struct hda_codec *codec)
4608{
Takashi Iwai691f1fc2011-04-07 10:31:43 +02004609 alc_auto_setup_eapd(codec, false);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004610}
4611
Hector Martinf5de24b2009-12-20 22:51:31 +01004612static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4613{
4614 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004615 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004616 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004617 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004618 return 0;
4619}
4620#endif
4621
Takashi Iwaie044c392008-10-27 16:56:24 +01004622#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004623static int alc_resume(struct hda_codec *codec)
4624{
Takashi Iwai1c716152011-04-07 10:37:16 +02004625 msleep(150); /* to avoid pop noise */
Takashi Iwaie044c392008-10-27 16:56:24 +01004626 codec->patch_ops.init(codec);
4627 snd_hda_codec_resume_amp(codec);
4628 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004629 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004630 return 0;
4631}
Takashi Iwaie044c392008-10-27 16:56:24 +01004632#endif
4633
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634/*
4635 */
Takashi Iwaia9111322011-05-02 11:30:18 +02004636static const struct hda_codec_ops alc_patch_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 .build_controls = alc_build_controls,
4638 .build_pcms = alc_build_pcms,
4639 .init = alc_init,
4640 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004641 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004642#ifdef SND_HDA_NEEDS_RESUME
4643 .resume = alc_resume,
4644#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004645#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004646 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004647 .check_power_status = alc_check_power_status,
4648#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004649 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650};
4651
Kailang Yangc027ddc2010-03-19 11:33:06 +01004652/* replace the codec chip_name with the given string */
4653static int alc_codec_rename(struct hda_codec *codec, const char *name)
4654{
4655 kfree(codec->chip_name);
4656 codec->chip_name = kstrdup(name, GFP_KERNEL);
4657 if (!codec->chip_name) {
4658 alc_free(codec);
4659 return -ENOMEM;
4660 }
4661 return 0;
4662}
4663
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004664/*
4665 * Test configuration for debugging
4666 *
4667 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4668 * enum controls.
4669 */
4670#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004671static const hda_nid_t alc880_test_dac_nids[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004672 0x02, 0x03, 0x04, 0x05
4673};
4674
Takashi Iwaia9111322011-05-02 11:30:18 +02004675static const struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004676 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004677 .items = {
4678 { "In-1", 0x0 },
4679 { "In-2", 0x1 },
4680 { "In-3", 0x2 },
4681 { "In-4", 0x3 },
4682 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004683 { "Front", 0x5 },
4684 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004685 },
4686};
4687
Takashi Iwaia9111322011-05-02 11:30:18 +02004688static const struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004689 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004690 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004691 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004692 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004693};
4694
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004695static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4696 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004697{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004698 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004699 "N/A", "Line Out", "HP Out",
4700 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4701 };
4702 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4703 uinfo->count = 1;
4704 uinfo->value.enumerated.items = 8;
4705 if (uinfo->value.enumerated.item >= 8)
4706 uinfo->value.enumerated.item = 7;
4707 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4708 return 0;
4709}
4710
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004711static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4712 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004713{
4714 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4715 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4716 unsigned int pin_ctl, item = 0;
4717
4718 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4719 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4720 if (pin_ctl & AC_PINCTL_OUT_EN) {
4721 if (pin_ctl & AC_PINCTL_HP_EN)
4722 item = 2;
4723 else
4724 item = 1;
4725 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4726 switch (pin_ctl & AC_PINCTL_VREFEN) {
4727 case AC_PINCTL_VREF_HIZ: item = 3; break;
4728 case AC_PINCTL_VREF_50: item = 4; break;
4729 case AC_PINCTL_VREF_GRD: item = 5; break;
4730 case AC_PINCTL_VREF_80: item = 6; break;
4731 case AC_PINCTL_VREF_100: item = 7; break;
4732 }
4733 }
4734 ucontrol->value.enumerated.item[0] = item;
4735 return 0;
4736}
4737
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004738static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4739 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004740{
4741 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4742 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004743 static const unsigned int ctls[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004744 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4745 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4746 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4747 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4748 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4749 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4750 };
4751 unsigned int old_ctl, new_ctl;
4752
4753 old_ctl = snd_hda_codec_read(codec, nid, 0,
4754 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4755 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4756 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004757 int val;
4758 snd_hda_codec_write_cache(codec, nid, 0,
4759 AC_VERB_SET_PIN_WIDGET_CONTROL,
4760 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004761 val = ucontrol->value.enumerated.item[0] >= 3 ?
4762 HDA_AMP_MUTE : 0;
4763 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4764 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004765 return 1;
4766 }
4767 return 0;
4768}
4769
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004770static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4771 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004772{
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02004773 static const char * const texts[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004774 "Front", "Surround", "CLFE", "Side"
4775 };
4776 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4777 uinfo->count = 1;
4778 uinfo->value.enumerated.items = 4;
4779 if (uinfo->value.enumerated.item >= 4)
4780 uinfo->value.enumerated.item = 3;
4781 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4782 return 0;
4783}
4784
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004785static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4786 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004787{
4788 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4789 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4790 unsigned int sel;
4791
4792 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4793 ucontrol->value.enumerated.item[0] = sel & 3;
4794 return 0;
4795}
4796
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004797static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4798 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004799{
4800 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4801 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4802 unsigned int sel;
4803
4804 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4805 if (ucontrol->value.enumerated.item[0] != sel) {
4806 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004807 snd_hda_codec_write_cache(codec, nid, 0,
4808 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004809 return 1;
4810 }
4811 return 0;
4812}
4813
4814#define PIN_CTL_TEST(xname,nid) { \
4815 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4816 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004817 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004818 .info = alc_test_pin_ctl_info, \
4819 .get = alc_test_pin_ctl_get, \
4820 .put = alc_test_pin_ctl_put, \
4821 .private_value = nid \
4822 }
4823
4824#define PIN_SRC_TEST(xname,nid) { \
4825 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4826 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004827 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004828 .info = alc_test_pin_src_info, \
4829 .get = alc_test_pin_src_get, \
4830 .put = alc_test_pin_src_put, \
4831 .private_value = nid \
4832 }
4833
Takashi Iwaia9111322011-05-02 11:30:18 +02004834static const struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004835 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4836 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4837 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4838 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004839 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4840 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4841 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4842 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004843 PIN_CTL_TEST("Front Pin Mode", 0x14),
4844 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4845 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4846 PIN_CTL_TEST("Side Pin Mode", 0x17),
4847 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4848 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4849 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4850 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4851 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4852 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4853 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4854 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4855 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4856 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4857 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4858 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4859 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4860 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4861 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4862 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4863 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4864 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004865 {
4866 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4867 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004868 .info = alc_ch_mode_info,
4869 .get = alc_ch_mode_get,
4870 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004871 },
4872 { } /* end */
4873};
4874
Takashi Iwaia9111322011-05-02 11:30:18 +02004875static const struct hda_verb alc880_test_init_verbs[] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004876 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004877 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4878 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4879 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4880 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4881 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4882 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4883 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4884 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004885 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004886 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4887 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4888 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4889 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004890 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004891 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4892 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4893 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4894 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004895 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004896 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4897 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4898 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4899 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004900 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004901 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4902 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004903 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4904 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4905 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004906 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004907 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4908 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4909 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4910 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004911 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004912 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004913 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004914 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004915 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004916 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004917 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004918 /* Analog input/passthru */
4919 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4920 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4921 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4922 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4923 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004924 { }
4925};
4926#endif
4927
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928/*
4929 */
4930
Takashi Iwaiea734962011-01-17 11:29:34 +01004931static const char * const alc880_models[ALC880_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004932 [ALC880_3ST] = "3stack",
4933 [ALC880_TCL_S700] = "tcl",
4934 [ALC880_3ST_DIG] = "3stack-digout",
4935 [ALC880_CLEVO] = "clevo",
4936 [ALC880_5ST] = "5stack",
4937 [ALC880_5ST_DIG] = "5stack-digout",
4938 [ALC880_W810] = "w810",
4939 [ALC880_Z71V] = "z71v",
4940 [ALC880_6ST] = "6stack",
4941 [ALC880_6ST_DIG] = "6stack-digout",
4942 [ALC880_ASUS] = "asus",
4943 [ALC880_ASUS_W1V] = "asus-w1v",
4944 [ALC880_ASUS_DIG] = "asus-dig",
4945 [ALC880_ASUS_DIG2] = "asus-dig2",
4946 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004947 [ALC880_UNIWILL_P53] = "uniwill-p53",
4948 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004949 [ALC880_F1734] = "F1734",
4950 [ALC880_LG] = "lg",
4951 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004952 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004953#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004954 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004955#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004956 [ALC880_AUTO] = "auto",
4957};
4958
Takashi Iwaia9111322011-05-02 11:30:18 +02004959static const struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004960 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004961 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4962 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4963 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4964 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4965 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4966 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4967 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4968 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004969 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004970 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4971 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4972 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4973 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4974 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4975 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4976 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4977 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4978 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4979 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004980 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004981 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4982 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4983 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004984 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004985 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004986 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4987 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004988 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4989 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004990 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4991 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4992 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4993 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004994 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4995 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004996 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004997 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004998 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Justin P. Mattocka2e2bc22011-02-24 22:16:02 -08004999 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005000 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
5001 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005002 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005003 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005004 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005005 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005006 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02005007 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04005008 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005009 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005010 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005011 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05005012 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005013 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005014 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005015 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
5016 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
5017 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
5018 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005019 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
5020 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005021 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005022 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005023 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
5024 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005025 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
5026 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
5027 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01005028 /* default Intel */
5029 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01005030 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
5031 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032 {}
5033};
5034
Takashi Iwai16ded522005-06-10 19:58:24 +02005035/*
Kailang Yangdf694da2005-12-05 19:42:22 +01005036 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02005037 */
Takashi Iwaia9111322011-05-02 11:30:18 +02005038static const struct alc_config_preset alc880_presets[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02005039 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005040 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005041 .init_verbs = { alc880_volume_init_verbs,
5042 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005043 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02005044 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005045 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5046 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005047 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005048 .input_mux = &alc880_capture_source,
5049 },
5050 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005051 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005052 .init_verbs = { alc880_volume_init_verbs,
5053 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005054 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02005055 .dac_nids = alc880_dac_nids,
5056 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005057 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5058 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005059 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005060 .input_mux = &alc880_capture_source,
5061 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005062 [ALC880_TCL_S700] = {
5063 .mixers = { alc880_tcl_s700_mixer },
5064 .init_verbs = { alc880_volume_init_verbs,
5065 alc880_pin_tcl_S700_init_verbs,
5066 alc880_gpio2_init_verbs },
5067 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5068 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005069 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
5070 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01005071 .hp_nid = 0x03,
5072 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5073 .channel_mode = alc880_2_jack_modes,
5074 .input_mux = &alc880_capture_source,
5075 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005076 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005077 .mixers = { alc880_three_stack_mixer,
5078 alc880_five_stack_mixer},
5079 .init_verbs = { alc880_volume_init_verbs,
5080 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005081 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5082 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005083 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5084 .channel_mode = alc880_fivestack_modes,
5085 .input_mux = &alc880_capture_source,
5086 },
5087 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005088 .mixers = { alc880_three_stack_mixer,
5089 alc880_five_stack_mixer },
5090 .init_verbs = { alc880_volume_init_verbs,
5091 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005092 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5093 .dac_nids = alc880_dac_nids,
5094 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005095 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
5096 .channel_mode = alc880_fivestack_modes,
5097 .input_mux = &alc880_capture_source,
5098 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005099 [ALC880_6ST] = {
5100 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005101 .init_verbs = { alc880_volume_init_verbs,
5102 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02005103 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5104 .dac_nids = alc880_6st_dac_nids,
5105 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5106 .channel_mode = alc880_sixstack_modes,
5107 .input_mux = &alc880_6stack_capture_source,
5108 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005109 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005110 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005111 .init_verbs = { alc880_volume_init_verbs,
5112 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005113 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
5114 .dac_nids = alc880_6st_dac_nids,
5115 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005116 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
5117 .channel_mode = alc880_sixstack_modes,
5118 .input_mux = &alc880_6stack_capture_source,
5119 },
5120 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005121 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005122 .init_verbs = { alc880_volume_init_verbs,
5123 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005124 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005125 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
5126 .dac_nids = alc880_w810_dac_nids,
5127 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005128 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
5129 .channel_mode = alc880_w810_modes,
5130 .input_mux = &alc880_capture_source,
5131 },
5132 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005133 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005134 .init_verbs = { alc880_volume_init_verbs,
5135 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005136 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
5137 .dac_nids = alc880_z71v_dac_nids,
5138 .dig_out_nid = ALC880_DIGOUT_NID,
5139 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005140 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5141 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02005142 .input_mux = &alc880_capture_source,
5143 },
5144 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005145 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005146 .init_verbs = { alc880_volume_init_verbs,
5147 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005148 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
5149 .dac_nids = alc880_f1734_dac_nids,
5150 .hp_nid = 0x02,
5151 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5152 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01005153 .input_mux = &alc880_f1734_capture_source,
5154 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005155 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005156 .init_hook = alc_hp_automute,
Takashi Iwai16ded522005-06-10 19:58:24 +02005157 },
5158 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005159 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005160 .init_verbs = { alc880_volume_init_verbs,
5161 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005162 alc880_gpio1_init_verbs },
5163 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5164 .dac_nids = alc880_asus_dac_nids,
5165 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5166 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005167 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005168 .input_mux = &alc880_capture_source,
5169 },
5170 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005171 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005172 .init_verbs = { alc880_volume_init_verbs,
5173 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005174 alc880_gpio1_init_verbs },
5175 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5176 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005177 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005178 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5179 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005180 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005181 .input_mux = &alc880_capture_source,
5182 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005183 [ALC880_ASUS_DIG2] = {
5184 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005185 .init_verbs = { alc880_volume_init_verbs,
5186 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01005187 alc880_gpio2_init_verbs }, /* use GPIO2 */
5188 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5189 .dac_nids = alc880_asus_dac_nids,
5190 .dig_out_nid = ALC880_DIGOUT_NID,
5191 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5192 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005193 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005194 .input_mux = &alc880_capture_source,
5195 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005196 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005197 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005198 .init_verbs = { alc880_volume_init_verbs,
5199 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005200 alc880_gpio1_init_verbs },
5201 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5202 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005203 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005204 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5205 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005206 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005207 .input_mux = &alc880_capture_source,
5208 },
5209 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005210 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02005211 .init_verbs = { alc880_volume_init_verbs,
5212 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005213 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5214 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02005215 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005216 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
5217 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005218 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02005219 .input_mux = &alc880_capture_source,
5220 },
Kailang Yangccc656c2006-10-17 12:32:26 +02005221 [ALC880_UNIWILL] = {
5222 .mixers = { alc880_uniwill_mixer },
5223 .init_verbs = { alc880_volume_init_verbs,
5224 alc880_uniwill_init_verbs },
5225 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5226 .dac_nids = alc880_asus_dac_nids,
5227 .dig_out_nid = ALC880_DIGOUT_NID,
5228 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5229 .channel_mode = alc880_threestack_modes,
5230 .need_dac_fix = 1,
5231 .input_mux = &alc880_capture_source,
5232 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005233 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02005234 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02005235 },
5236 [ALC880_UNIWILL_P53] = {
5237 .mixers = { alc880_uniwill_p53_mixer },
5238 .init_verbs = { alc880_volume_init_verbs,
5239 alc880_uniwill_p53_init_verbs },
5240 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
5241 .dac_nids = alc880_asus_dac_nids,
5242 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005243 .channel_mode = alc880_threestack_modes,
5244 .input_mux = &alc880_capture_source,
5245 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005246 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005247 .init_hook = alc_hp_automute,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005248 },
5249 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005250 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005251 .init_verbs = { alc880_volume_init_verbs,
5252 alc880_uniwill_p53_init_verbs,
5253 alc880_beep_init_verbs },
5254 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5255 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02005256 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01005257 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5258 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02005259 .input_mux = &alc880_capture_source,
5260 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005261 .setup = alc880_uniwill_p53_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005262 .init_hook = alc_hp_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +02005263 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005264 [ALC880_CLEVO] = {
5265 .mixers = { alc880_three_stack_mixer },
5266 .init_verbs = { alc880_volume_init_verbs,
5267 alc880_pin_clevo_init_verbs },
5268 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5269 .dac_nids = alc880_dac_nids,
5270 .hp_nid = 0x03,
5271 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
5272 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005273 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01005274 .input_mux = &alc880_capture_source,
5275 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005276 [ALC880_LG] = {
5277 .mixers = { alc880_lg_mixer },
5278 .init_verbs = { alc880_volume_init_verbs,
5279 alc880_lg_init_verbs },
5280 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
5281 .dac_nids = alc880_lg_dac_nids,
5282 .dig_out_nid = ALC880_DIGOUT_NID,
5283 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
5284 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02005285 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005286 .input_mux = &alc880_lg_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005287 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005288 .setup = alc880_lg_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005289 .init_hook = alc_hp_automute,
Takashi Iwaicb53c622007-08-10 17:21:45 +02005290#ifdef CONFIG_SND_HDA_POWER_SAVE
5291 .loopbacks = alc880_lg_loopbacks,
5292#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005293 },
Takashi Iwaid6815182006-03-23 16:06:23 +01005294 [ALC880_LG_LW] = {
5295 .mixers = { alc880_lg_lw_mixer },
5296 .init_verbs = { alc880_volume_init_verbs,
5297 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005298 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01005299 .dac_nids = alc880_dac_nids,
5300 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02005301 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
5302 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01005303 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +02005304 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005305 .setup = alc880_lg_lw_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +02005306 .init_hook = alc_hp_automute,
Takashi Iwaid6815182006-03-23 16:06:23 +01005307 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005308 [ALC880_MEDION_RIM] = {
5309 .mixers = { alc880_medion_rim_mixer },
5310 .init_verbs = { alc880_volume_init_verbs,
5311 alc880_medion_rim_init_verbs,
5312 alc_gpio2_init_verbs },
5313 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
5314 .dac_nids = alc880_dac_nids,
5315 .dig_out_nid = ALC880_DIGOUT_NID,
5316 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
5317 .channel_mode = alc880_2_jack_modes,
5318 .input_mux = &alc880_medion_rim_capture_source,
5319 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02005320 .setup = alc880_medion_rim_setup,
5321 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02005322 },
Takashi Iwai16ded522005-06-10 19:58:24 +02005323#ifdef CONFIG_SND_DEBUG
5324 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005325 .mixers = { alc880_test_mixer },
5326 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02005327 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
5328 .dac_nids = alc880_test_dac_nids,
5329 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02005330 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
5331 .channel_mode = alc880_test_modes,
5332 .input_mux = &alc880_test_capture_source,
5333 },
5334#endif
5335};
5336
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005337/*
5338 * Automatic parse of I/O pins from the BIOS configuration
5339 */
5340
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005341enum {
5342 ALC_CTL_WIDGET_VOL,
5343 ALC_CTL_WIDGET_MUTE,
5344 ALC_CTL_BIND_MUTE,
5345};
Takashi Iwaia9111322011-05-02 11:30:18 +02005346static const struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005347 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
5348 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01005349 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005350};
5351
Takashi Iwaice764ab2011-04-27 16:35:23 +02005352static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
5353{
5354 snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
5355 return snd_array_new(&spec->kctls);
5356}
5357
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005358/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005359static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005360 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005361{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01005362 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005363
Takashi Iwaice764ab2011-04-27 16:35:23 +02005364 knew = alc_kcontrol_new(spec);
Takashi Iwai603c4012008-07-30 15:01:44 +02005365 if (!knew)
5366 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005367 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07005368 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005369 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005370 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005371 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01005372 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01005373 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005374 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005375 return 0;
5376}
5377
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005378static int add_control_with_pfx(struct alc_spec *spec, int type,
5379 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005380 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005381{
5382 char name[32];
5383 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005384 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005385}
5386
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005387#define add_pb_vol_ctrl(spec, type, pfx, val) \
5388 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5389#define add_pb_sw_ctrl(spec, type, pfx, val) \
5390 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5391#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5392 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5393#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5394 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005395
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005396#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5397#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5398#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5399#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005400#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5401#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5402#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5403#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5404#define ALC880_PIN_CD_NID 0x1c
5405
Takashi Iwai6843ca12011-06-24 11:03:58 +02005406static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
5407 bool can_be_master, int *index)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005408{
Takashi Iwaice764ab2011-04-27 16:35:23 +02005409 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai6843ca12011-06-24 11:03:58 +02005410 static const char * const chname[4] = {
5411 "Front", "Surround", NULL /*CLFE*/, "Side"
5412 };
Takashi Iwaice764ab2011-04-27 16:35:23 +02005413
Takashi Iwai6843ca12011-06-24 11:03:58 +02005414 *index = 0;
Takashi Iwaice764ab2011-04-27 16:35:23 +02005415 if (cfg->line_outs == 1 && !spec->multi_ios &&
5416 !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005417 return "Master";
5418
5419 switch (cfg->line_out_type) {
5420 case AUTO_PIN_SPEAKER_OUT:
David Henningssonebbeb3d2011-03-04 14:08:30 +01005421 if (cfg->line_outs == 1)
5422 return "Speaker";
5423 break;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005424 case AUTO_PIN_HP_OUT:
Takashi Iwai6843ca12011-06-24 11:03:58 +02005425 /* for multi-io case, only the primary out */
5426 if (ch && spec->multi_ios)
5427 break;
5428 *index = ch;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005429 return "Headphone";
5430 default:
Takashi Iwaice764ab2011-04-27 16:35:23 +02005431 if (cfg->line_outs == 1 && !spec->multi_ios)
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005432 return "PCM";
5433 break;
5434 }
Takashi Iwai6843ca12011-06-24 11:03:58 +02005435 return chname[ch];
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +01005436}
5437
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005438/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005439static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005440 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005441 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005442{
Kailang Yangdf694da2005-12-05 19:42:22 +01005443 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005444
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005445 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005446 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5447 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005448 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005449 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005450 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5451 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005452 return err;
5453 return 0;
5454}
5455
Takashi Iwai05f5f472009-08-25 13:10:18 +02005456static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005457{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005458 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5459 return (pincap & AC_PINCAP_IN) != 0;
5460}
5461
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005462static int alc_auto_fill_adc_caps(struct hda_codec *codec)
Takashi Iwaib7821702011-07-06 15:12:46 +02005463{
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005464 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02005465 hda_nid_t nid;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005466 hda_nid_t *adc_nids = spec->private_adc_nids;
5467 hda_nid_t *cap_nids = spec->private_capsrc_nids;
5468 int max_nums = ARRAY_SIZE(spec->private_adc_nids);
5469 bool indep_capsrc = false;
Takashi Iwaib7821702011-07-06 15:12:46 +02005470 int i, nums = 0;
5471
5472 nid = codec->start_nid;
5473 for (i = 0; i < codec->num_nodes; i++, nid++) {
5474 hda_nid_t src;
5475 const hda_nid_t *list;
5476 unsigned int caps = get_wcaps(codec, nid);
5477 int type = get_wcaps_type(caps);
5478
5479 if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
5480 continue;
5481 adc_nids[nums] = nid;
5482 cap_nids[nums] = nid;
5483 src = nid;
5484 for (;;) {
5485 int n;
5486 type = get_wcaps_type(get_wcaps(codec, src));
5487 if (type == AC_WID_PIN)
5488 break;
5489 if (type == AC_WID_AUD_SEL) {
5490 cap_nids[nums] = src;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005491 indep_capsrc = true;
Takashi Iwaib7821702011-07-06 15:12:46 +02005492 break;
5493 }
5494 n = snd_hda_get_conn_list(codec, src, &list);
5495 if (n > 1) {
5496 cap_nids[nums] = src;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005497 indep_capsrc = true;
Takashi Iwaib7821702011-07-06 15:12:46 +02005498 break;
5499 } else if (n != 1)
5500 break;
5501 src = *list;
5502 }
5503 if (++nums >= max_nums)
5504 break;
5505 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005506 spec->adc_nids = spec->private_adc_nids;
Takashi Iwai21268962011-07-07 15:01:13 +02005507 spec->capsrc_nids = spec->private_capsrc_nids;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005508 spec->num_adc_nids = nums;
Takashi Iwaib7821702011-07-06 15:12:46 +02005509 return nums;
5510}
5511
Takashi Iwai05f5f472009-08-25 13:10:18 +02005512/* create playback/capture controls for input pins */
Takashi Iwaib7821702011-07-06 15:12:46 +02005513static int alc_auto_create_input_ctls(struct hda_codec *codec)
Takashi Iwai05f5f472009-08-25 13:10:18 +02005514{
5515 struct alc_spec *spec = codec->spec;
Takashi Iwaib7821702011-07-06 15:12:46 +02005516 const struct auto_pin_cfg *cfg = &spec->autocfg;
5517 hda_nid_t mixer = spec->mixer_nid;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005518 struct hda_input_mux *imux = &spec->private_imux[0];
Takashi Iwaib7821702011-07-06 15:12:46 +02005519 int num_adcs;
Takashi Iwaib7821702011-07-06 15:12:46 +02005520 int i, c, err, idx, type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005521 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005522
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005523 num_adcs = alc_auto_fill_adc_caps(codec);
Takashi Iwaib7821702011-07-06 15:12:46 +02005524 if (num_adcs < 0)
5525 return 0;
5526
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005527 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005528 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005529 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005530
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005531 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005532 if (!alc_is_input_pin(codec, pin))
5533 continue;
5534
David Henningsson5322bf22011-01-05 11:03:56 +01005535 label = hda_get_autocfg_input_label(codec, cfg, i);
5536 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005537 type_idx++;
5538 else
5539 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005540 prev_label = label;
5541
Takashi Iwai05f5f472009-08-25 13:10:18 +02005542 if (mixer) {
5543 idx = get_connection_index(codec, mixer, pin);
5544 if (idx >= 0) {
5545 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005546 label, type_idx,
5547 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005548 if (err < 0)
5549 return err;
5550 }
5551 }
5552
Takashi Iwaib7821702011-07-06 15:12:46 +02005553 for (c = 0; c < num_adcs; c++) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005554 hda_nid_t cap = spec->capsrc_nids ?
5555 spec->capsrc_nids[c] : spec->adc_nids[c];
5556 idx = get_connection_index(codec, cap, pin);
Takashi Iwaib7821702011-07-06 15:12:46 +02005557 if (idx >= 0) {
Takashi Iwai21268962011-07-07 15:01:13 +02005558 spec->imux_pins[imux->num_items] = pin;
Takashi Iwaib7821702011-07-06 15:12:46 +02005559 snd_hda_add_imux_item(imux, label, idx, NULL);
5560 break;
5561 }
5562 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005563 }
Takashi Iwai21268962011-07-07 15:01:13 +02005564
5565 spec->num_mux_defs = 1;
5566 spec->input_mux = imux;
5567
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005568 return 0;
5569}
5570
Takashi Iwai343a04b2011-07-06 14:28:39 +02005571static int alc_auto_fill_dac_nids(struct hda_codec *codec);
5572static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
5573 const struct auto_pin_cfg *cfg);
5574static int alc_auto_create_hp_out(struct hda_codec *codec);
5575static int alc_auto_create_speaker_out(struct hda_codec *codec);
5576static void alc_auto_init_multi_out(struct hda_codec *codec);
5577static void alc_auto_init_extra_out(struct hda_codec *codec);
5578
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005579static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5580 unsigned int pin_type)
5581{
5582 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5583 pin_type);
5584 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005585 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5586 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005587}
5588
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005589static int get_pin_type(int line_out_type)
5590{
5591 if (line_out_type == AUTO_PIN_HP_OUT)
5592 return PIN_HP;
5593 else
5594 return PIN_OUT;
5595}
5596
Takashi Iwai0a7f5322011-07-06 15:15:12 +02005597static void alc_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005598{
5599 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005600 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005601 int i;
5602
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005603 for (i = 0; i < cfg->num_inputs; i++) {
5604 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005605 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005606 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005607 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005608 snd_hda_codec_write(codec, nid, 0,
5609 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005610 AMP_OUT_MUTE);
5611 }
5612 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005613
5614 /* mute all loopback inputs */
5615 if (spec->mixer_nid) {
5616 int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
5617 for (i = 0; i < nums; i++)
5618 snd_hda_codec_write(codec, spec->mixer_nid, 0,
5619 AC_VERB_SET_AMP_GAIN_MUTE,
5620 AMP_IN_MUTE(i));
5621 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005622}
5623
Takashi Iwaicb053a82011-06-27 11:32:07 +02005624static int alc_auto_add_multi_channel_mode(struct hda_codec *codec,
5625 int (*fill_dac)(struct hda_codec *));
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005626static void alc_remove_invalid_adc_nids(struct hda_codec *codec);
Takashi Iwaif970de22011-07-06 17:39:59 +02005627static void alc_auto_init_input_src(struct hda_codec *codec);
Takashi Iwaice764ab2011-04-27 16:35:23 +02005628
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005629/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005630/* return 1 if successful, 0 if the proper config is not found,
5631 * or a negative error code
5632 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005633static int alc880_parse_auto_config(struct hda_codec *codec)
5634{
5635 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005636 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005637 static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005638
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005639 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5640 alc880_ignore);
5641 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005642 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005643 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005644 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005645
Takashi Iwai343a04b2011-07-06 14:28:39 +02005646 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005647 if (err < 0)
5648 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005649 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +02005650 if (err < 0)
5651 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005652 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005653 if (err < 0)
5654 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005655 err = alc_auto_create_hp_out(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005656 if (err < 0)
5657 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005658 err = alc_auto_create_speaker_out(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005659 if (err < 0)
5660 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +02005661 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005662 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005663 return err;
5664
5665 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5666
Takashi Iwai757899a2010-07-30 10:48:14 +02005667 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005668
Takashi Iwai603c4012008-07-30 15:01:44 +02005669 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005670 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005671
Takashi Iwai21268962011-07-07 15:01:13 +02005672 alc_remove_invalid_adc_nids(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005673
Kailang Yang6227cdc2010-02-25 08:36:52 +01005674 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai21268962011-07-07 15:01:13 +02005675 alc_auto_check_switches(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005676
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005677 return 1;
5678}
5679
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005680/* additional initialization for auto-configuration model */
5681static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005682{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005683 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +02005684 alc_auto_init_multi_out(codec);
5685 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +02005686 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +02005687 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005688 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005689 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005690 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005691}
5692
Takashi Iwai748cce42010-08-04 07:37:39 +02005693/* select or unmute the given capsrc route */
5694static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5695 int idx)
5696{
5697 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5698 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5699 HDA_AMP_MUTE, 0);
Takashi Iwai21268962011-07-07 15:01:13 +02005700 } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
Takashi Iwai748cce42010-08-04 07:37:39 +02005701 snd_hda_codec_write_cache(codec, cap, 0,
5702 AC_VERB_SET_CONNECT_SEL, idx);
5703 }
5704}
5705
Takashi Iwai840b64c2010-07-13 22:49:01 +02005706/* set the default connection to that pin */
5707static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5708{
5709 struct alc_spec *spec = codec->spec;
5710 int i;
5711
Takashi Iwai8ed99d92011-05-17 12:05:02 +02005712 if (!pin)
5713 return 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005714 for (i = 0; i < spec->num_adc_nids; i++) {
5715 hda_nid_t cap = spec->capsrc_nids ?
5716 spec->capsrc_nids[i] : spec->adc_nids[i];
5717 int idx;
5718
5719 idx = get_connection_index(codec, cap, pin);
5720 if (idx < 0)
5721 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005722 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005723 return i; /* return the found index */
5724 }
5725 return -1; /* not found */
5726}
5727
Takashi Iwai584c0c42011-03-10 12:51:11 +01005728/* initialize some special cases for input sources */
5729static void alc_init_special_input_src(struct hda_codec *codec)
5730{
5731 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02005732 int i;
5733
5734 for (i = 0; i < spec->autocfg.num_inputs; i++)
5735 init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin);
Takashi Iwai584c0c42011-03-10 12:51:11 +01005736}
5737
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005738static void set_capture_mixer(struct hda_codec *codec)
5739{
5740 struct alc_spec *spec = codec->spec;
Takashi Iwaia9111322011-05-02 11:30:18 +02005741 static const struct snd_kcontrol_new *caps[2][3] = {
Takashi Iwaia23b6882009-03-23 15:21:36 +01005742 { alc_capture_mixer_nosrc1,
5743 alc_capture_mixer_nosrc2,
5744 alc_capture_mixer_nosrc3 },
5745 { alc_capture_mixer1,
5746 alc_capture_mixer2,
5747 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005748 };
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005749
5750 /* check whether either of ADC or MUX has a volume control */
5751 if (!(query_amp_caps(codec, spec->adc_nids[0], HDA_INPUT) &
5752 AC_AMPCAP_NUM_STEPS)) {
5753 if (!spec->capsrc_nids)
5754 return; /* no volume */
5755 if (!(query_amp_caps(codec, spec->capsrc_nids[0], HDA_OUTPUT) &
5756 AC_AMPCAP_NUM_STEPS))
5757 return; /* no volume in capsrc, too */
5758 spec->vol_in_capsrc = 1;
5759 }
5760
5761 if (spec->num_adc_nids > 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005762 int mux = 0;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005763 int num_adcs = 0;
Takashi Iwai21268962011-07-07 15:01:13 +02005764
5765 if (spec->input_mux && spec->input_mux->num_items > 1)
5766 mux = 1;
5767 if (spec->auto_mic) {
Takashi Iwai584c0c42011-03-10 12:51:11 +01005768 num_adcs = 1;
Takashi Iwai21268962011-07-07 15:01:13 +02005769 mux = 0;
5770 } else if (spec->dyn_adc_switch)
5771 num_adcs = 1;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005772 if (!num_adcs) {
5773 if (spec->num_adc_nids > 3)
5774 spec->num_adc_nids = 3;
5775 else if (!spec->num_adc_nids)
5776 return;
5777 num_adcs = spec->num_adc_nids;
5778 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005779 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005780 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005781}
5782
Takashi Iwai21268962011-07-07 15:01:13 +02005783/* check whether dynamic ADC-switching is available */
5784static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
5785{
5786 struct alc_spec *spec = codec->spec;
5787 struct hda_input_mux *imux = &spec->private_imux[0];
5788 int i, n, idx;
5789 hda_nid_t cap, pin;
5790
5791 if (imux != spec->input_mux) /* no dynamic imux? */
5792 return false;
5793
5794 for (n = 0; n < spec->num_adc_nids; n++) {
5795 cap = spec->private_capsrc_nids[n];
5796 for (i = 0; i < imux->num_items; i++) {
5797 pin = spec->imux_pins[i];
5798 if (!pin)
5799 return false;
5800 if (get_connection_index(codec, cap, pin) < 0)
5801 break;
5802 }
5803 if (i >= imux->num_items)
5804 return false; /* no ADC-switch is needed */
5805 }
5806
5807 for (i = 0; i < imux->num_items; i++) {
5808 pin = spec->imux_pins[i];
5809 for (n = 0; n < spec->num_adc_nids; n++) {
5810 cap = spec->private_capsrc_nids[n];
5811 idx = get_connection_index(codec, cap, pin);
5812 if (idx >= 0) {
5813 imux->items[i].index = idx;
5814 spec->dyn_adc_idx[i] = n;
5815 break;
5816 }
5817 }
5818 }
5819
5820 snd_printdd("realtek: enabling ADC switching\n");
5821 spec->dyn_adc_switch = 1;
5822 return true;
5823}
5824
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005825/* filter out invalid adc_nids (and capsrc_nids) that don't give all
5826 * active input pins
5827 */
5828static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
Takashi Iwai66946352010-03-29 17:21:45 +02005829{
5830 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +02005831 const struct hda_input_mux *imux;
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005832 hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
5833 hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
5834 int i, n, nums;
Takashi Iwai66946352010-03-29 17:21:45 +02005835
Takashi Iwai21268962011-07-07 15:01:13 +02005836 imux = spec->input_mux;
5837 if (!imux)
5838 return;
5839 if (spec->dyn_adc_switch)
5840 return;
5841
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005842 nums = 0;
5843 for (n = 0; n < spec->num_adc_nids; n++) {
5844 hda_nid_t cap = spec->private_capsrc_nids[n];
Takashi Iwai21268962011-07-07 15:01:13 +02005845 int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
5846 for (i = 0; i < imux->num_items; i++) {
5847 hda_nid_t pin = spec->imux_pins[i];
5848 if (pin) {
5849 if (get_connection_index(codec, cap, pin) < 0)
5850 break;
5851 } else if (num_conns <= imux->items[i].index)
Takashi Iwai66946352010-03-29 17:21:45 +02005852 break;
5853 }
Takashi Iwai21268962011-07-07 15:01:13 +02005854 if (i >= imux->num_items) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005855 adc_nids[nums] = spec->private_adc_nids[n];
5856 capsrc_nids[nums++] = cap;
Takashi Iwai66946352010-03-29 17:21:45 +02005857 }
5858 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005859 if (!nums) {
Takashi Iwai21268962011-07-07 15:01:13 +02005860 /* check whether ADC-switch is possible */
5861 if (!alc_check_dyn_adc_switch(codec)) {
5862 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
5863 " using fallback 0x%x\n",
5864 codec->chip_name, spec->private_adc_nids[0]);
5865 spec->num_adc_nids = 1;
5866 spec->auto_mic = 0;
5867 return;
5868 }
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005869 } else if (nums != spec->num_adc_nids) {
5870 memcpy(spec->private_adc_nids, adc_nids,
5871 nums * sizeof(hda_nid_t));
5872 memcpy(spec->private_capsrc_nids, capsrc_nids,
5873 nums * sizeof(hda_nid_t));
5874 spec->num_adc_nids = nums;
Takashi Iwai66946352010-03-29 17:21:45 +02005875 }
Takashi Iwai21268962011-07-07 15:01:13 +02005876
5877 if (spec->auto_mic)
5878 alc_auto_mic_check_imux(codec); /* check auto-mic setups */
5879 else if (spec->input_mux->num_items == 1)
5880 spec->num_adc_nids = 1; /* reduce to a single ADC */
Takashi Iwai66946352010-03-29 17:21:45 +02005881}
5882
Takashi Iwai67d634c2009-11-16 15:35:59 +01005883#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005884#define set_beep_amp(spec, nid, idx, dir) \
5885 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005886
Takashi Iwaia9111322011-05-02 11:30:18 +02005887static const struct snd_pci_quirk beep_white_list[] = {
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005888 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005889 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Daniel Corderoa7e985e2011-04-29 08:18:06 +02005890 SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
Madis Janson39dfe132011-05-19 18:32:41 +02005891 SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005892 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005893 {}
5894};
5895
5896static inline int has_cdefine_beep(struct hda_codec *codec)
5897{
5898 struct alc_spec *spec = codec->spec;
5899 const struct snd_pci_quirk *q;
5900 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5901 if (q)
5902 return q->value;
5903 return spec->cdefine.enable_pcbeep;
5904}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005905#else
5906#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005907#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005908#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005909
5910/*
5911 * OK, here we have finally the patch for ALC880
5912 */
5913
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914static int patch_alc880(struct hda_codec *codec)
5915{
5916 struct alc_spec *spec;
5917 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005918 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005920 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921 if (spec == NULL)
5922 return -ENOMEM;
5923
5924 codec->spec = spec;
5925
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02005926 spec->mixer_nid = 0x0b;
5927
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005928 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5929 alc880_models,
5930 alc880_cfg_tbl);
5931 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005932 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5933 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005934 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 }
5936
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005937 if (board_config == ALC880_AUTO) {
5938 /* automatic parse from the BIOS config */
5939 err = alc880_parse_auto_config(codec);
5940 if (err < 0) {
5941 alc_free(codec);
5942 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005943 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005944 printk(KERN_INFO
5945 "hda_codec: Cannot set up configuration "
5946 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005947 board_config = ALC880_3ST;
5948 }
5949 }
5950
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005951 err = snd_hda_attach_beep_device(codec, 0x1);
5952 if (err < 0) {
5953 alc_free(codec);
5954 return err;
5955 }
5956
Kailang Yangdf694da2005-12-05 19:42:22 +01005957 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005958 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005960 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005961 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +02005962 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02005963 alc_remove_invalid_adc_nids(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005964 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005965 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005966 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967
Takashi Iwai2134ea42008-01-10 16:53:55 +01005968 spec->vmaster_nid = 0x0c;
5969
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005971 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005972 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005973#ifdef CONFIG_SND_HDA_POWER_SAVE
5974 if (!spec->loopback.amplist)
5975 spec->loopback.amplist = alc880_loopbacks;
5976#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977
5978 return 0;
5979}
5980
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005981
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982/*
5983 * ALC260 support
5984 */
5985
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005986static const hda_nid_t alc260_dac_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005987 /* front */
5988 0x02,
5989};
5990
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005991static const hda_nid_t alc260_adc_nids[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005992 /* ADC0 */
5993 0x04,
5994};
5995
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02005996static const hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005997 /* ADC1 */
5998 0x05,
5999};
6000
Jonathan Woithed57fdac2006-02-28 11:38:35 +01006001/* NIDs used when simultaneous access to both ADCs makes sense. Note that
6002 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
6003 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006004static const hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006005 /* ADC0, ADC1 */
6006 0x04, 0x05
6007};
6008
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006009#define ALC260_DIGOUT_NID 0x03
6010#define ALC260_DIGIN_NID 0x06
6011
Takashi Iwaia9111322011-05-02 11:30:18 +02006012static const struct hda_input_mux alc260_capture_source = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02006013 .num_items = 4,
6014 .items = {
6015 { "Mic", 0x0 },
6016 { "Front Mic", 0x1 },
6017 { "Line", 0x2 },
6018 { "CD", 0x4 },
6019 },
6020};
6021
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006022/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006023 * headphone jack and the internal CD lines since these are the only pins at
6024 * which audio can appear. For flexibility, also allow the option of
6025 * recording the mixer output on the second ADC (ADC0 doesn't have a
6026 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006027 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006028static const struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006029 {
6030 .num_items = 3,
6031 .items = {
6032 { "Mic/Line", 0x0 },
6033 { "CD", 0x4 },
6034 { "Headphone", 0x2 },
6035 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006036 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006037 {
6038 .num_items = 4,
6039 .items = {
6040 { "Mic/Line", 0x0 },
6041 { "CD", 0x4 },
6042 { "Headphone", 0x2 },
6043 { "Mixer", 0x5 },
6044 },
6045 },
6046
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006047};
6048
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006049/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
6050 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006051 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006052static const struct hda_input_mux alc260_acer_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006053 {
6054 .num_items = 4,
6055 .items = {
6056 { "Mic", 0x0 },
6057 { "Line", 0x2 },
6058 { "CD", 0x4 },
6059 { "Headphone", 0x5 },
6060 },
6061 },
6062 {
6063 .num_items = 5,
6064 .items = {
6065 { "Mic", 0x0 },
6066 { "Line", 0x2 },
6067 { "CD", 0x4 },
6068 { "Headphone", 0x6 },
6069 { "Mixer", 0x5 },
6070 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006071 },
6072};
Michael Schwingencc959482009-02-22 18:58:45 +01006073
6074/* Maxdata Favorit 100XS */
Takashi Iwaia9111322011-05-02 11:30:18 +02006075static const struct hda_input_mux alc260_favorit100_capture_sources[2] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006076 {
6077 .num_items = 2,
6078 .items = {
6079 { "Line/Mic", 0x0 },
6080 { "CD", 0x4 },
6081 },
6082 },
6083 {
6084 .num_items = 3,
6085 .items = {
6086 { "Line/Mic", 0x0 },
6087 { "CD", 0x4 },
6088 { "Mixer", 0x5 },
6089 },
6090 },
6091};
6092
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093/*
6094 * This is just place-holder, so there's something for alc_build_pcms to look
6095 * at when it calculates the maximum number of channels. ALC260 has no mixer
6096 * element which allows changing the channel mode, so the verb list is
6097 * never used.
6098 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006099static const struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 { 2, NULL },
6101};
6102
Kailang Yangdf694da2005-12-05 19:42:22 +01006103
6104/* Mixer combinations
6105 *
6106 * basic: base_output + input + pc_beep + capture
6107 * HP: base_output + input + capture_alt
6108 * HP_3013: hp_3013 + input + capture
6109 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006110 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01006111 */
6112
Takashi Iwaia9111322011-05-02 11:30:18 +02006113static const struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02006114 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006115 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006116 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6117 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6118 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6119 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6120 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006121};
Kailang Yangdf694da2005-12-05 19:42:22 +01006122
Takashi Iwaia9111322011-05-02 11:30:18 +02006123static const struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6125 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6126 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6127 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6128 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6129 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6130 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
6131 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 { } /* end */
6133};
6134
Takashi Iwaibec15c32008-01-28 18:16:30 +01006135/* update HP, line and mono out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +02006136static void alc260_hp_master_update(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006137{
Takashi Iwaie9427962011-04-28 15:46:07 +02006138 update_speakers(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006139}
6140
6141static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
6142 struct snd_ctl_elem_value *ucontrol)
6143{
6144 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6145 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006146 *ucontrol->value.integer.value = !spec->master_mute;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006147 return 0;
6148}
6149
6150static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
6151 struct snd_ctl_elem_value *ucontrol)
6152{
6153 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
6154 struct alc_spec *spec = codec->spec;
Takashi Iwaie9427962011-04-28 15:46:07 +02006155 int val = !*ucontrol->value.integer.value;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006156
Takashi Iwaie9427962011-04-28 15:46:07 +02006157 if (val == spec->master_mute)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006158 return 0;
Takashi Iwaie9427962011-04-28 15:46:07 +02006159 spec->master_mute = val;
6160 alc260_hp_master_update(codec);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006161 return 1;
6162}
6163
Takashi Iwaia9111322011-05-02 11:30:18 +02006164static const struct snd_kcontrol_new alc260_hp_output_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006165 {
6166 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6167 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006168 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006169 .info = snd_ctl_boolean_mono_info,
6170 .get = alc260_hp_master_sw_get,
6171 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006172 },
6173 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6174 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
6175 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6176 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
6177 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
6178 HDA_OUTPUT),
6179 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6180 { } /* end */
6181};
6182
Takashi Iwaia9111322011-05-02 11:30:18 +02006183static const struct hda_verb alc260_hp_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006184 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6185 {},
6186};
6187
Takashi Iwaie9427962011-04-28 15:46:07 +02006188static void alc260_hp_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006189{
6190 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006191
Takashi Iwaie9427962011-04-28 15:46:07 +02006192 spec->autocfg.hp_pins[0] = 0x0f;
6193 spec->autocfg.speaker_pins[0] = 0x10;
6194 spec->autocfg.speaker_pins[1] = 0x11;
6195 spec->automute = 1;
6196 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006197}
6198
Takashi Iwaia9111322011-05-02 11:30:18 +02006199static const struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006200 {
6201 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
6202 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01006203 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006204 .info = snd_ctl_boolean_mono_info,
6205 .get = alc260_hp_master_sw_get,
6206 .put = alc260_hp_master_sw_put,
Takashi Iwaibec15c32008-01-28 18:16:30 +01006207 },
Kailang Yangdf694da2005-12-05 19:42:22 +01006208 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6209 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6210 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
6211 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
6212 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6213 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01006214 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6215 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02006216 { } /* end */
6217};
6218
Takashi Iwaie9427962011-04-28 15:46:07 +02006219static void alc260_hp_3013_setup(struct hda_codec *codec)
6220{
6221 struct alc_spec *spec = codec->spec;
6222
6223 spec->autocfg.hp_pins[0] = 0x15;
6224 spec->autocfg.speaker_pins[0] = 0x10;
6225 spec->autocfg.speaker_pins[1] = 0x11;
6226 spec->automute = 1;
6227 spec->automute_mode = ALC_AUTOMUTE_PIN;
6228}
6229
Takashi Iwaia9111322011-05-02 11:30:18 +02006230static const struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
Kailang Yang3f878302008-08-26 13:02:23 +02006231 .ops = &snd_hda_bind_vol,
6232 .values = {
6233 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
6234 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
6235 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
6236 0
6237 },
6238};
6239
Takashi Iwaia9111322011-05-02 11:30:18 +02006240static const struct hda_bind_ctls alc260_dc7600_bind_switch = {
Kailang Yang3f878302008-08-26 13:02:23 +02006241 .ops = &snd_hda_bind_sw,
6242 .values = {
6243 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
6244 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
6245 0
6246 },
6247};
6248
Takashi Iwaia9111322011-05-02 11:30:18 +02006249static const struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006250 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
6251 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
6252 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
6253 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
6254 { } /* end */
6255};
6256
Takashi Iwaia9111322011-05-02 11:30:18 +02006257static const struct hda_verb alc260_hp_3013_unsol_verbs[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01006258 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6259 {},
6260};
6261
Takashi Iwaie9427962011-04-28 15:46:07 +02006262static void alc260_hp_3012_setup(struct hda_codec *codec)
Takashi Iwaibec15c32008-01-28 18:16:30 +01006263{
6264 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006265
Takashi Iwaie9427962011-04-28 15:46:07 +02006266 spec->autocfg.hp_pins[0] = 0x10;
6267 spec->autocfg.speaker_pins[0] = 0x0f;
6268 spec->autocfg.speaker_pins[1] = 0x11;
6269 spec->autocfg.speaker_pins[2] = 0x15;
6270 spec->automute = 1;
6271 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang3f878302008-08-26 13:02:23 +02006272}
6273
6274/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006275 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6276 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006277static const struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006278 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006279 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006280 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006281 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6282 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6283 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6284 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006285 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006286 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6287 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006288 { } /* end */
6289};
6290
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006291/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6292 * versions of the ALC260 don't act on requests to enable mic bias from NID
6293 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6294 * datasheet doesn't mention this restriction. At this stage it's not clear
6295 * whether this behaviour is intentional or is a hardware bug in chip
6296 * revisions available in early 2006. Therefore for now allow the
6297 * "Headphone Jack Mode" control to span all choices, but if it turns out
6298 * that the lack of mic bias for this NID is intentional we could change the
6299 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6300 *
6301 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6302 * don't appear to make the mic bias available from the "line" jack, even
6303 * though the NID used for this jack (0x14) can supply it. The theory is
6304 * that perhaps Acer have included blocking capacitors between the ALC260
6305 * and the output jack. If this turns out to be the case for all such
6306 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6307 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006308 *
6309 * The C20x Tablet series have a mono internal speaker which is controlled
6310 * via the chip's Mono sum widget and pin complex, so include the necessary
6311 * controls for such models. On models without a "mono speaker" the control
6312 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006313 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006314static const struct snd_kcontrol_new alc260_acer_mixer[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006315 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6316 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006317 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006318 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006319 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006320 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006321 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006322 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6323 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6324 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6325 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6326 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6327 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6328 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6329 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006330 { } /* end */
6331};
6332
Michael Schwingencc959482009-02-22 18:58:45 +01006333/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6334 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006335static const struct snd_kcontrol_new alc260_favorit100_mixer[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006336 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6337 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6338 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6339 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6340 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6341 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6342 { } /* end */
6343};
6344
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006345/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6346 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6347 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006348static const struct snd_kcontrol_new alc260_will_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006349 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6350 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6351 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6352 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6353 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6354 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6355 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6356 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6357 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6358 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006359 { } /* end */
6360};
6361
6362/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6363 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6364 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006365static const struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006366 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6367 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6368 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6369 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6370 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6371 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6372 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6373 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6374 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6375 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6376 { } /* end */
6377};
6378
Kailang Yangdf694da2005-12-05 19:42:22 +01006379/*
6380 * initialization verbs
6381 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006382static const struct hda_verb alc260_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006384 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006386 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006388 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006390 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006392 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006394 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006396 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006398 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006400 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6401 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006402 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 /* set connection select to line in (default select for this ADC) */
6404 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006405 /* mute capture amp left and right */
6406 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6407 /* set connection select to line in (default select for this ADC) */
6408 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006409 /* set vol=0 Line-Out mixer amp left and right */
6410 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6411 /* unmute pin widget amp left and right (no gain on this amp) */
6412 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6413 /* set vol=0 HP mixer amp left and right */
6414 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6415 /* unmute pin widget amp left and right (no gain on this amp) */
6416 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6417 /* set vol=0 Mono mixer amp left and right */
6418 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6419 /* unmute pin widget amp left and right (no gain on this amp) */
6420 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6421 /* unmute LINE-2 out pin */
6422 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006423 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6424 * Line In 2 = 0x03
6425 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006426 /* mute analog inputs */
6427 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6428 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6429 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6430 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6431 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006432 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006433 /* mute Front out path */
6434 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6435 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6436 /* mute Headphone out path */
6437 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6438 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6439 /* mute Mono out path */
6440 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6441 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442 { }
6443};
6444
Takashi Iwai474167d2006-05-17 17:17:43 +02006445#if 0 /* should be identical with alc260_init_verbs? */
Takashi Iwaia9111322011-05-02 11:30:18 +02006446static const struct hda_verb alc260_hp_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006447 /* Headphone and output */
6448 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6449 /* mono output */
6450 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6451 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6452 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6453 /* Mic2 (front panel) pin widget for input and vref at 80% */
6454 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6455 /* Line In pin widget for input */
6456 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6457 /* Line-2 pin widget for output */
6458 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6459 /* CD pin widget for input */
6460 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6461 /* unmute amp left and right */
6462 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6463 /* set connection select to line in (default select for this ADC) */
6464 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6465 /* unmute Line-Out mixer amp left and right (volume = 0) */
6466 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6467 /* mute pin widget amp left and right (no gain on this amp) */
6468 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6469 /* unmute HP mixer amp left and right (volume = 0) */
6470 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6471 /* mute pin widget amp left and right (no gain on this amp) */
6472 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006473 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6474 * Line In 2 = 0x03
6475 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006476 /* mute analog inputs */
6477 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6478 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6479 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6480 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6481 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006482 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6483 /* Unmute Front out path */
6484 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6485 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6486 /* Unmute Headphone out path */
6487 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6488 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6489 /* Unmute Mono out path */
6490 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6491 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6492 { }
6493};
Takashi Iwai474167d2006-05-17 17:17:43 +02006494#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006495
Takashi Iwaia9111322011-05-02 11:30:18 +02006496static const struct hda_verb alc260_hp_3013_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01006497 /* Line out and output */
6498 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6499 /* mono output */
6500 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6501 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6502 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6503 /* Mic2 (front panel) pin widget for input and vref at 80% */
6504 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6505 /* Line In pin widget for input */
6506 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6507 /* Headphone pin widget for output */
6508 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6509 /* CD pin widget for input */
6510 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6511 /* unmute amp left and right */
6512 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6513 /* set connection select to line in (default select for this ADC) */
6514 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6515 /* unmute Line-Out mixer amp left and right (volume = 0) */
6516 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6517 /* mute pin widget amp left and right (no gain on this amp) */
6518 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6519 /* unmute HP mixer amp left and right (volume = 0) */
6520 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6521 /* mute pin widget amp left and right (no gain on this amp) */
6522 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006523 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6524 * Line In 2 = 0x03
6525 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006526 /* mute analog inputs */
6527 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6528 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6529 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6530 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6531 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006532 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6533 /* Unmute Front out path */
6534 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6535 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6536 /* Unmute Headphone out path */
6537 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6538 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6539 /* Unmute Mono out path */
6540 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6541 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6542 { }
6543};
6544
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006545/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006546 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6547 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006548 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006549static const struct hda_verb alc260_fujitsu_init_verbs[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006550 /* Disable all GPIOs */
6551 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6552 /* Internal speaker is connected to headphone pin */
6553 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6554 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6555 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006556 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6557 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6558 /* Ensure all other unused pins are disabled and muted. */
6559 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6560 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006561 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006562 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006563 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006564 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6565 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6566 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006567
Jonathan Woithef7ace402006-02-28 11:46:14 +01006568 /* Disable digital (SPDIF) pins */
6569 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6570 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006571
Kailang Yangea1fb292008-08-26 12:58:38 +02006572 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006573 * when acting as an output.
6574 */
6575 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6576
6577 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006578 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6579 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6580 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6581 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6582 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6583 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6584 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6585 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6586 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006587
Jonathan Woithef7ace402006-02-28 11:46:14 +01006588 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6589 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6590 /* Unmute Line1 pin widget output buffer since it starts as an output.
6591 * If the pin mode is changed by the user the pin mode control will
6592 * take care of enabling the pin's input/output buffers as needed.
6593 * Therefore there's no need to enable the input buffer at this
6594 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006595 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006596 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006597 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006598 * mixer ctrl)
6599 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006600 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006601
Jonathan Woithef7ace402006-02-28 11:46:14 +01006602 /* Mute capture amp left and right */
6603 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006604 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006605 * in (on mic1 pin)
6606 */
6607 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006608
Jonathan Woithef7ace402006-02-28 11:46:14 +01006609 /* Do the same for the second ADC: mute capture input amp and
6610 * set ADC connection to line in (on mic1 pin)
6611 */
6612 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6613 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006614
Jonathan Woithef7ace402006-02-28 11:46:14 +01006615 /* Mute all inputs to mixer widget (even unconnected ones) */
6616 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6617 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6618 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6619 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6620 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6621 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6622 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6623 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006624
6625 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006626};
6627
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006628/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6629 * similar laptops (adapted from Fujitsu init verbs).
6630 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006631static const struct hda_verb alc260_acer_init_verbs[] = {
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006632 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6633 * the headphone jack. Turn this on and rely on the standard mute
6634 * methods whenever the user wants to turn these outputs off.
6635 */
6636 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6637 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6638 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6639 /* Internal speaker/Headphone jack is connected to Line-out pin */
6640 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6641 /* Internal microphone/Mic jack is connected to Mic1 pin */
6642 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6643 /* Line In jack is connected to Line1 pin */
6644 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006645 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6646 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006647 /* Ensure all other unused pins are disabled and muted. */
6648 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6649 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006650 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6651 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6652 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6653 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6654 /* Disable digital (SPDIF) pins */
6655 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6656 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6657
Kailang Yangea1fb292008-08-26 12:58:38 +02006658 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006659 * bus when acting as outputs.
6660 */
6661 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6662 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6663
6664 /* Start with output sum widgets muted and their output gains at min */
6665 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6666 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6667 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6668 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6669 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6670 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6671 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6672 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6673 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6674
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006675 /* Unmute Line-out pin widget amp left and right
6676 * (no equiv mixer ctrl)
6677 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006678 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006679 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6680 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006681 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6682 * inputs. If the pin mode is changed by the user the pin mode control
6683 * will take care of enabling the pin's input/output buffers as needed.
6684 * Therefore there's no need to enable the input buffer at this
6685 * stage.
6686 */
6687 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6688 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6689
6690 /* Mute capture amp left and right */
6691 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6692 /* Set ADC connection select to match default mixer setting - mic
6693 * (on mic1 pin)
6694 */
6695 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6696
6697 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006698 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006699 */
6700 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006701 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006702
6703 /* Mute all inputs to mixer widget (even unconnected ones) */
6704 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6705 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6706 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6707 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6708 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6709 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6710 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6711 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6712
6713 { }
6714};
6715
Michael Schwingencc959482009-02-22 18:58:45 +01006716/* Initialisation sequence for Maxdata Favorit 100XS
6717 * (adapted from Acer init verbs).
6718 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006719static const struct hda_verb alc260_favorit100_init_verbs[] = {
Michael Schwingencc959482009-02-22 18:58:45 +01006720 /* GPIO 0 enables the output jack.
6721 * 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 /* Line/Mic input jack is connected to Mic1 pin */
6728 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6729 /* Ensure all other unused pins are disabled and muted. */
6730 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6731 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6732 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6733 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6734 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6735 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6736 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6737 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6738 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6739 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6740 /* Disable digital (SPDIF) pins */
6741 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6742 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6743
6744 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6745 * bus when acting as outputs.
6746 */
6747 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6748 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6749
6750 /* Start with output sum widgets muted and their output gains at min */
6751 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6752 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6753 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6754 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6755 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6756 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6757 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6758 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6759 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6760
6761 /* Unmute Line-out pin widget amp left and right
6762 * (no equiv mixer ctrl)
6763 */
6764 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6765 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6766 * inputs. If the pin mode is changed by the user the pin mode control
6767 * will take care of enabling the pin's input/output buffers as needed.
6768 * Therefore there's no need to enable the input buffer at this
6769 * stage.
6770 */
6771 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6772
6773 /* Mute capture amp left and right */
6774 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6775 /* Set ADC connection select to match default mixer setting - mic
6776 * (on mic1 pin)
6777 */
6778 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6779
6780 /* Do similar with the second ADC: mute capture input amp and
6781 * set ADC connection to mic to match ALSA's default state.
6782 */
6783 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6784 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6785
6786 /* Mute all inputs to mixer widget (even unconnected ones) */
6787 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6788 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6789 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6790 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6791 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6792 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6793 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6794 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6795
6796 { }
6797};
6798
Takashi Iwaia9111322011-05-02 11:30:18 +02006799static const struct hda_verb alc260_will_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006800 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6801 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6802 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6803 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6804 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6805 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6806 {}
6807};
6808
Takashi Iwaia9111322011-05-02 11:30:18 +02006809static const struct hda_verb alc260_replacer_672v_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006810 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6811 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6812 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6813
6814 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6815 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6816 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6817
6818 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6819 {}
6820};
6821
6822/* toggle speaker-output according to the hp-jack state */
6823static void alc260_replacer_672v_automute(struct hda_codec *codec)
6824{
6825 unsigned int present;
6826
6827 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006828 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006829 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006830 snd_hda_codec_write_cache(codec, 0x01, 0,
6831 AC_VERB_SET_GPIO_DATA, 1);
6832 snd_hda_codec_write_cache(codec, 0x0f, 0,
6833 AC_VERB_SET_PIN_WIDGET_CONTROL,
6834 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006835 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006836 snd_hda_codec_write_cache(codec, 0x01, 0,
6837 AC_VERB_SET_GPIO_DATA, 0);
6838 snd_hda_codec_write_cache(codec, 0x0f, 0,
6839 AC_VERB_SET_PIN_WIDGET_CONTROL,
6840 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006841 }
6842}
6843
6844static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6845 unsigned int res)
6846{
6847 if ((res >> 26) == ALC880_HP_EVENT)
6848 alc260_replacer_672v_automute(codec);
6849}
6850
Takashi Iwaia9111322011-05-02 11:30:18 +02006851static const struct hda_verb alc260_hp_dc7600_verbs[] = {
Kailang Yang3f878302008-08-26 13:02:23 +02006852 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6853 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6854 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6855 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6856 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6857 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6858 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6859 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6860 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6861 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6862 {}
6863};
6864
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006865/* Test configuration for debugging, modelled after the ALC880 test
6866 * configuration.
6867 */
6868#ifdef CONFIG_SND_DEBUG
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006869static const hda_nid_t alc260_test_dac_nids[1] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006870 0x02,
6871};
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02006872static const hda_nid_t alc260_test_adc_nids[2] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006873 0x04, 0x05,
6874};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006875/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006876 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006877 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006878 */
Takashi Iwaia9111322011-05-02 11:30:18 +02006879static const struct hda_input_mux alc260_test_capture_sources[2] = {
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006880 {
6881 .num_items = 7,
6882 .items = {
6883 { "MIC1 pin", 0x0 },
6884 { "MIC2 pin", 0x1 },
6885 { "LINE1 pin", 0x2 },
6886 { "LINE2 pin", 0x3 },
6887 { "CD pin", 0x4 },
6888 { "LINE-OUT pin", 0x5 },
6889 { "HP-OUT pin", 0x6 },
6890 },
6891 },
6892 {
6893 .num_items = 8,
6894 .items = {
6895 { "MIC1 pin", 0x0 },
6896 { "MIC2 pin", 0x1 },
6897 { "LINE1 pin", 0x2 },
6898 { "LINE2 pin", 0x3 },
6899 { "CD pin", 0x4 },
6900 { "Mixer", 0x5 },
6901 { "LINE-OUT pin", 0x6 },
6902 { "HP-OUT pin", 0x7 },
6903 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006904 },
6905};
Takashi Iwaia9111322011-05-02 11:30:18 +02006906static const struct snd_kcontrol_new alc260_test_mixer[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006907 /* Output driver widgets */
6908 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6909 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6910 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6911 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6912 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6913 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6914
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006915 /* Modes for retasking pin widgets
6916 * Note: the ALC260 doesn't seem to act on requests to enable mic
6917 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6918 * mention this restriction. At this stage it's not clear whether
6919 * this behaviour is intentional or is a hardware bug in chip
6920 * revisions available at least up until early 2006. Therefore for
6921 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6922 * choices, but if it turns out that the lack of mic bias for these
6923 * NIDs is intentional we could change their modes from
6924 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6925 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006926 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6927 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6928 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6929 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6930 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6931 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6932
6933 /* Loopback mixer controls */
6934 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6935 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6936 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6937 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6938 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6939 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6940 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6941 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6942 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6943 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006944 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6945 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6946 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6947 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006948
6949 /* Controls for GPIO pins, assuming they are configured as outputs */
6950 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6951 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6952 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6953 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6954
Jonathan Woithe92621f12006-02-28 11:47:47 +01006955 /* Switches to allow the digital IO pins to be enabled. The datasheet
6956 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006957 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006958 */
6959 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6960 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6961
Jonathan Woithef8225f62008-01-08 12:16:54 +01006962 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6963 * this output to turn on an external amplifier.
6964 */
6965 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6966 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6967
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006968 { } /* end */
6969};
Takashi Iwaia9111322011-05-02 11:30:18 +02006970static const struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006971 /* Enable all GPIOs as outputs with an initial value of 0 */
6972 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6973 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6974 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6975
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006976 /* Enable retasking pins as output, initially without power amp */
6977 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6978 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6979 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6980 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6981 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6982 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6983
Jonathan Woithe92621f12006-02-28 11:47:47 +01006984 /* Disable digital (SPDIF) pins initially, but users can enable
6985 * them via a mixer switch. In the case of SPDIF-out, this initverb
6986 * payload also sets the generation to 0, output to be in "consumer"
6987 * PCM format, copyright asserted, no pre-emphasis and no validity
6988 * control.
6989 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006990 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6991 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6992
Kailang Yangea1fb292008-08-26 12:58:38 +02006993 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006994 * OUT1 sum bus when acting as an output.
6995 */
6996 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6997 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6998 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6999 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
7000
7001 /* Start with output sum widgets muted and their output gains at min */
7002 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7003 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7004 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7005 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7006 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7007 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7008 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7009 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7010 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
7011
Jonathan Woithecdcd9262006-02-28 11:36:42 +01007012 /* Unmute retasking pin widget output buffers since the default
7013 * state appears to be output. As the pin mode is changed by the
7014 * user the pin mode control will take care of enabling the pin's
7015 * input/output buffers as needed.
7016 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007017 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7018 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7019 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7020 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7021 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7022 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7023 /* Also unmute the mono-out pin widget */
7024 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7025
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007026 /* Mute capture amp left and right */
7027 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01007028 /* Set ADC connection select to match default mixer setting (mic1
7029 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007030 */
7031 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
7032
7033 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01007034 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007035 */
7036 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7037 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
7038
7039 /* Mute all inputs to mixer widget (even unconnected ones) */
7040 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
7041 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
7042 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
7043 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
7044 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
7045 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
7046 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
7047 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
7048
7049 { }
7050};
7051#endif
7052
Kailang Yangdf694da2005-12-05 19:42:22 +01007053/*
7054 * for BIOS auto-configuration
7055 */
7056
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007057/* convert from pin to volume-mixer widget */
7058static hda_nid_t alc260_pin_to_vol_mix(hda_nid_t nid)
7059{
7060 if (nid >= 0x0f && nid <= 0x11)
7061 return nid - 0x7;
7062 else if (nid >= 0x12 && nid <= 0x15)
7063 return 0x08;
7064 else
7065 return 0;
7066}
7067
Kailang Yangdf694da2005-12-05 19:42:22 +01007068static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02007069 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01007070{
7071 hda_nid_t nid_vol;
7072 unsigned long vol_val, sw_val;
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007073 int chs, err;
Kailang Yangdf694da2005-12-05 19:42:22 +01007074
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007075 nid_vol = alc260_pin_to_vol_mix(nid);
7076 if (!nid_vol)
Kailang Yangdf694da2005-12-05 19:42:22 +01007077 return 0; /* N/A */
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007078 if (nid == 0x11)
7079 chs = 2;
7080 else
7081 chs = 3;
7082 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, chs, 0, HDA_OUTPUT);
7083 sw_val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
Kailang Yangea1fb292008-08-26 12:58:38 +02007084
Takashi Iwai863b4512008-10-21 17:01:47 +02007085 if (!(*vol_bits & (1 << nid_vol))) {
7086 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007087 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02007088 if (err < 0)
7089 return err;
7090 *vol_bits |= (1 << nid_vol);
7091 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02007092 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007093 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007094 return err;
7095 return 1;
7096}
7097
7098/* add playback controls from the parsed DAC table */
7099static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
7100 const struct auto_pin_cfg *cfg)
7101{
7102 hda_nid_t nid;
7103 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02007104 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007105
7106 spec->multiout.num_dacs = 1;
7107 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +02007108 spec->private_dac_nids[0] = 0x02;
Kailang Yangdf694da2005-12-05 19:42:22 +01007109
7110 nid = cfg->line_out_pins[0];
7111 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02007112 const char *pfx;
Takashi Iwai2e925dd2011-06-24 11:27:22 +02007113 int index;
7114 pfx = alc_get_line_out_pfx(spec, 0, true, &index);
Takashi Iwai23112d62009-08-25 16:07:08 +02007115 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007116 if (err < 0)
7117 return err;
7118 }
7119
Takashi Iwai82bc9552006-03-21 11:24:42 +01007120 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007121 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007122 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007123 if (err < 0)
7124 return err;
7125 }
7126
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007127 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007128 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02007129 err = alc260_add_playback_controls(spec, nid, "Headphone",
7130 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01007131 if (err < 0)
7132 return err;
7133 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007134 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01007135}
7136
Kailang Yangdf694da2005-12-05 19:42:22 +01007137static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
7138 hda_nid_t nid, int pin_type,
7139 int sel_idx)
7140{
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007141 hda_nid_t mix;
7142
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007143 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01007144 /* need the manual connection? */
7145 if (nid >= 0x12) {
7146 int idx = nid - 0x12;
7147 snd_hda_codec_write(codec, idx + 0x0b, 0,
7148 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01007149 }
Kailang Yangdf694da2005-12-05 19:42:22 +01007150
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007151 mix = alc260_pin_to_vol_mix(nid);
7152 if (!mix)
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007153 return;
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007154 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007155 AMP_OUT_ZERO);
Takashi Iwai6d86b4f2011-06-27 15:00:48 +02007156 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7157 AMP_IN_UNMUTE(0));
7158 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
7159 AMP_IN_UNMUTE(1));
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007160}
7161
Kailang Yangdf694da2005-12-05 19:42:22 +01007162static void alc260_auto_init_multi_out(struct hda_codec *codec)
7163{
7164 struct alc_spec *spec = codec->spec;
7165 hda_nid_t nid;
7166
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007167 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007168 if (nid) {
7169 int pin_type = get_pin_type(spec->autocfg.line_out_type);
7170 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
7171 }
Kailang Yangea1fb292008-08-26 12:58:38 +02007172
Takashi Iwai82bc9552006-03-21 11:24:42 +01007173 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007174 if (nid)
7175 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
7176
Takashi Iwaieb06ed82006-09-20 17:10:27 +02007177 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007178 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02007179 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007180}
Kailang Yangdf694da2005-12-05 19:42:22 +01007181
Kailang Yangdf694da2005-12-05 19:42:22 +01007182static int alc260_parse_auto_config(struct hda_codec *codec)
7183{
7184 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007185 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007186 static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +01007187
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007188 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7189 alc260_ignore);
7190 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007191 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007192 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7193 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007194 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007195 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007196 return 0; /* can't find valid BIOS pin config */
Takashi Iwaib7821702011-07-06 15:12:46 +02007197 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007198 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007199 return err;
7200
7201 spec->multiout.max_channels = 2;
7202
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007203 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007204 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007205 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007206 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007207
Takashi Iwai21268962011-07-07 15:01:13 +02007208 alc_remove_invalid_adc_nids(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02007209
Kailang Yang6227cdc2010-02-25 08:36:52 +01007210 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai21268962011-07-07 15:01:13 +02007211 alc_auto_check_switches(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007212
Kailang Yangdf694da2005-12-05 19:42:22 +01007213 return 1;
7214}
7215
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007216/* additional initialization for auto-configuration model */
7217static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007218{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007219 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007220 alc260_auto_init_multi_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +02007221 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +02007222 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007223 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007224 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007225 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007226}
7227
Takashi Iwaicb53c622007-08-10 17:21:45 +02007228#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +02007229static const struct hda_amp_list alc260_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02007230 { 0x07, HDA_INPUT, 0 },
7231 { 0x07, HDA_INPUT, 1 },
7232 { 0x07, HDA_INPUT, 2 },
7233 { 0x07, HDA_INPUT, 3 },
7234 { 0x07, HDA_INPUT, 4 },
7235 { } /* end */
7236};
7237#endif
7238
Kailang Yangdf694da2005-12-05 19:42:22 +01007239/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007240 * Pin config fixes
7241 */
7242enum {
7243 PINFIX_HP_DC5750,
7244};
7245
Takashi Iwaifc091762010-08-04 23:53:36 +02007246static const struct alc_fixup alc260_fixups[] = {
7247 [PINFIX_HP_DC5750] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007248 .type = ALC_FIXUP_PINS,
7249 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +02007250 { 0x11, 0x90130110 }, /* speaker */
7251 { }
7252 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007253 },
7254};
7255
Takashi Iwaia9111322011-05-02 11:30:18 +02007256static const struct snd_pci_quirk alc260_fixup_tbl[] = {
Takashi Iwaifc091762010-08-04 23:53:36 +02007257 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7258 {}
7259};
7260
7261/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007262 * ALC260 configurations
7263 */
Takashi Iwaiea734962011-01-17 11:29:34 +01007264static const char * const alc260_models[ALC260_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007265 [ALC260_BASIC] = "basic",
7266 [ALC260_HP] = "hp",
7267 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007268 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007269 [ALC260_FUJITSU_S702X] = "fujitsu",
7270 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007271 [ALC260_WILL] = "will",
7272 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007273 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007274#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007275 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007276#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007277 [ALC260_AUTO] = "auto",
7278};
7279
Takashi Iwaia9111322011-05-02 11:30:18 +02007280static const struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007281 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007282 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007283 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007284 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007285 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007286 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007287 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007288 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007289 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007290 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7291 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7292 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7293 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7294 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7295 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7296 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7297 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7298 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007299 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007300 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007301 {}
7302};
7303
Takashi Iwaia9111322011-05-02 11:30:18 +02007304static const struct alc_config_preset alc260_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007305 [ALC260_BASIC] = {
7306 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007307 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007308 .init_verbs = { alc260_init_verbs },
7309 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7310 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007311 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007312 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007313 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7314 .channel_mode = alc260_modes,
7315 .input_mux = &alc260_capture_source,
7316 },
7317 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007318 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007319 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007320 .init_verbs = { alc260_init_verbs,
7321 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007322 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7323 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007324 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7325 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007326 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7327 .channel_mode = alc260_modes,
7328 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007329 .unsol_event = alc_sku_unsol_event,
7330 .setup = alc260_hp_setup,
7331 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007332 },
Kailang Yang3f878302008-08-26 13:02:23 +02007333 [ALC260_HP_DC7600] = {
7334 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007335 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007336 .init_verbs = { alc260_init_verbs,
7337 alc260_hp_dc7600_verbs },
7338 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7339 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007340 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7341 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007342 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7343 .channel_mode = alc260_modes,
7344 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007345 .unsol_event = alc_sku_unsol_event,
7346 .setup = alc260_hp_3012_setup,
7347 .init_hook = alc_inithook,
Kailang Yang3f878302008-08-26 13:02:23 +02007348 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007349 [ALC260_HP_3013] = {
7350 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007351 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007352 .init_verbs = { alc260_hp_3013_init_verbs,
7353 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007354 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7355 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007356 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7357 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007358 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7359 .channel_mode = alc260_modes,
7360 .input_mux = &alc260_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +02007361 .unsol_event = alc_sku_unsol_event,
7362 .setup = alc260_hp_3013_setup,
7363 .init_hook = alc_inithook,
Kailang Yangdf694da2005-12-05 19:42:22 +01007364 },
7365 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007366 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007367 .init_verbs = { alc260_fujitsu_init_verbs },
7368 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7369 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007370 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7371 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007372 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7373 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007374 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7375 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007376 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007377 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007378 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007379 .init_verbs = { alc260_acer_init_verbs },
7380 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7381 .dac_nids = alc260_dac_nids,
7382 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7383 .adc_nids = alc260_dual_adc_nids,
7384 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7385 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007386 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7387 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007388 },
Michael Schwingencc959482009-02-22 18:58:45 +01007389 [ALC260_FAVORIT100] = {
7390 .mixers = { alc260_favorit100_mixer },
7391 .init_verbs = { alc260_favorit100_init_verbs },
7392 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7393 .dac_nids = alc260_dac_nids,
7394 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7395 .adc_nids = alc260_dual_adc_nids,
7396 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7397 .channel_mode = alc260_modes,
7398 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7399 .input_mux = alc260_favorit100_capture_sources,
7400 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007401 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007402 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007403 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7404 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7405 .dac_nids = alc260_dac_nids,
7406 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7407 .adc_nids = alc260_adc_nids,
7408 .dig_out_nid = ALC260_DIGOUT_NID,
7409 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7410 .channel_mode = alc260_modes,
7411 .input_mux = &alc260_capture_source,
7412 },
7413 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007414 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007415 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7416 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7417 .dac_nids = alc260_dac_nids,
7418 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7419 .adc_nids = alc260_adc_nids,
7420 .dig_out_nid = ALC260_DIGOUT_NID,
7421 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7422 .channel_mode = alc260_modes,
7423 .input_mux = &alc260_capture_source,
7424 .unsol_event = alc260_replacer_672v_unsol_event,
7425 .init_hook = alc260_replacer_672v_automute,
7426 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007427#ifdef CONFIG_SND_DEBUG
7428 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007429 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007430 .init_verbs = { alc260_test_init_verbs },
7431 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7432 .dac_nids = alc260_test_dac_nids,
7433 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7434 .adc_nids = alc260_test_adc_nids,
7435 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7436 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007437 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7438 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007439 },
7440#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007441};
7442
Linus Torvalds1da177e2005-04-16 15:20:36 -07007443static int patch_alc260(struct hda_codec *codec)
7444{
7445 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007446 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007447
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007448 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007449 if (spec == NULL)
7450 return -ENOMEM;
7451
7452 codec->spec = spec;
7453
Takashi Iwai1f0f4b82011-06-27 10:52:59 +02007454 spec->mixer_nid = 0x07;
7455
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007456 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7457 alc260_models,
7458 alc260_cfg_tbl);
7459 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007460 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007461 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007462 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007463 }
7464
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007465 if (board_config == ALC260_AUTO) {
7466 alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
7467 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
7468 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007469
Kailang Yangdf694da2005-12-05 19:42:22 +01007470 if (board_config == ALC260_AUTO) {
7471 /* automatic parse from the BIOS config */
7472 err = alc260_parse_auto_config(codec);
7473 if (err < 0) {
7474 alc_free(codec);
7475 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007476 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007477 printk(KERN_INFO
7478 "hda_codec: Cannot set up configuration "
7479 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007480 board_config = ALC260_BASIC;
7481 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007484 err = snd_hda_attach_beep_device(codec, 0x1);
7485 if (err < 0) {
7486 alc_free(codec);
7487 return err;
7488 }
7489
Kailang Yangdf694da2005-12-05 19:42:22 +01007490 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007491 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007492
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007493 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02007494 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +02007495 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +02007496 alc_remove_invalid_adc_nids(codec);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007497 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007498 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007499 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007500
Takashi Iwaib5bfbc62011-01-13 14:22:32 +01007501 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaifc091762010-08-04 23:53:36 +02007502
Takashi Iwai2134ea42008-01-10 16:53:55 +01007503 spec->vmaster_nid = 0x08;
7504
Linus Torvalds1da177e2005-04-16 15:20:36 -07007505 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007506 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007507 spec->init_hook = alc260_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +02007508 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007509#ifdef CONFIG_SND_HDA_POWER_SAVE
7510 if (!spec->loopback.amplist)
7511 spec->loopback.amplist = alc260_loopbacks;
7512#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007513
7514 return 0;
7515}
7516
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007517
Linus Torvalds1da177e2005-04-16 15:20:36 -07007518/*
Takashi Iwai49535502009-06-30 15:28:30 +02007519 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007520 *
7521 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7522 * configuration. Each pin widget can choose any input DACs and a mixer.
7523 * Each ADC is connected from a mixer of all inputs. This makes possible
7524 * 6-channel independent captures.
7525 *
7526 * In addition, an independent DAC for the multi-playback (not used in this
7527 * driver yet).
7528 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007529#define ALC882_DIGOUT_NID 0x06
7530#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007531#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7532#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7533#define ALC1200_DIGOUT_NID 0x10
7534
Linus Torvalds1da177e2005-04-16 15:20:36 -07007535
Takashi Iwaia9111322011-05-02 11:30:18 +02007536static const struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007537 { 8, NULL }
7538};
7539
Takashi Iwai49535502009-06-30 15:28:30 +02007540/* DACs */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007541static const hda_nid_t alc882_dac_nids[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007542 /* front, rear, clfe, rear_surr */
7543 0x02, 0x03, 0x04, 0x05
7544};
Takashi Iwai49535502009-06-30 15:28:30 +02007545#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007546
Takashi Iwai49535502009-06-30 15:28:30 +02007547/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007548#define alc882_adc_nids alc880_adc_nids
7549#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007550#define alc883_adc_nids alc882_adc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007551static const hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7552static const hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
Takashi Iwai49535502009-06-30 15:28:30 +02007553#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007554
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007555static const hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7556static const hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007557#define alc883_capsrc_nids alc882_capsrc_nids_alt
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02007558static const hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
Takashi Iwai49535502009-06-30 15:28:30 +02007559#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007560
Linus Torvalds1da177e2005-04-16 15:20:36 -07007561/* input MUX */
7562/* FIXME: should be a matrix-type input source selection */
7563
Takashi Iwaia9111322011-05-02 11:30:18 +02007564static const struct hda_input_mux alc882_capture_source = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565 .num_items = 4,
7566 .items = {
7567 { "Mic", 0x0 },
7568 { "Front Mic", 0x1 },
7569 { "Line", 0x2 },
7570 { "CD", 0x4 },
7571 },
7572};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007573
Takashi Iwai49535502009-06-30 15:28:30 +02007574#define alc883_capture_source alc882_capture_source
7575
Takashi Iwaia9111322011-05-02 11:30:18 +02007576static const struct hda_input_mux alc889_capture_source = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007577 .num_items = 3,
7578 .items = {
7579 { "Front Mic", 0x0 },
7580 { "Mic", 0x3 },
7581 { "Line", 0x2 },
7582 },
7583};
7584
Takashi Iwaia9111322011-05-02 11:30:18 +02007585static const struct hda_input_mux mb5_capture_source = {
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007586 .num_items = 3,
7587 .items = {
7588 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307589 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007590 { "CD", 0x4 },
7591 },
7592};
7593
Takashi Iwaia9111322011-05-02 11:30:18 +02007594static const struct hda_input_mux macmini3_capture_source = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007595 .num_items = 2,
7596 .items = {
7597 { "Line", 0x2 },
7598 { "CD", 0x4 },
7599 },
7600};
7601
Takashi Iwaia9111322011-05-02 11:30:18 +02007602static const struct hda_input_mux alc883_3stack_6ch_intel = {
Takashi Iwai49535502009-06-30 15:28:30 +02007603 .num_items = 4,
7604 .items = {
7605 { "Mic", 0x1 },
7606 { "Front Mic", 0x0 },
7607 { "Line", 0x2 },
7608 { "CD", 0x4 },
7609 },
7610};
7611
Takashi Iwaia9111322011-05-02 11:30:18 +02007612static const struct hda_input_mux alc883_lenovo_101e_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007613 .num_items = 2,
7614 .items = {
7615 { "Mic", 0x1 },
7616 { "Line", 0x2 },
7617 },
7618};
7619
Takashi Iwaia9111322011-05-02 11:30:18 +02007620static const struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007621 .num_items = 4,
7622 .items = {
7623 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007624 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007625 { "Line", 0x2 },
7626 { "CD", 0x4 },
7627 },
7628};
7629
Takashi Iwaia9111322011-05-02 11:30:18 +02007630static const struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007631 .num_items = 2,
7632 .items = {
7633 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007634 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007635 },
7636};
7637
Takashi Iwaia9111322011-05-02 11:30:18 +02007638static const struct hda_input_mux alc883_lenovo_sky_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007639 .num_items = 3,
7640 .items = {
7641 { "Mic", 0x0 },
7642 { "Front Mic", 0x1 },
7643 { "Line", 0x4 },
7644 },
7645};
7646
Takashi Iwaia9111322011-05-02 11:30:18 +02007647static const struct hda_input_mux alc883_asus_eee1601_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007648 .num_items = 2,
7649 .items = {
7650 { "Mic", 0x0 },
7651 { "Line", 0x2 },
7652 },
7653};
7654
Takashi Iwaia9111322011-05-02 11:30:18 +02007655static const struct hda_input_mux alc889A_mb31_capture_source = {
Takashi Iwai49535502009-06-30 15:28:30 +02007656 .num_items = 2,
7657 .items = {
7658 { "Mic", 0x0 },
7659 /* Front Mic (0x01) unused */
7660 { "Line", 0x2 },
7661 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007662 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007663 },
7664};
7665
Takashi Iwaia9111322011-05-02 11:30:18 +02007666static const struct hda_input_mux alc889A_imac91_capture_source = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007667 .num_items = 2,
7668 .items = {
7669 { "Mic", 0x01 },
7670 { "Line", 0x2 }, /* Not sure! */
7671 },
7672};
7673
Takashi Iwai49535502009-06-30 15:28:30 +02007674/*
7675 * 2ch mode
7676 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007677static const struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007678 { 2, NULL }
7679};
7680
Kailang Yangdf694da2005-12-05 19:42:22 +01007681/*
Kailang Yang272a5272007-05-14 11:00:38 +02007682 * 2ch mode
7683 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007684static const struct hda_verb alc882_3ST_ch2_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007685 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7686 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7687 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7688 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7689 { } /* end */
7690};
7691
7692/*
Takashi Iwai49535502009-06-30 15:28:30 +02007693 * 4ch mode
7694 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007695static const struct hda_verb alc882_3ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007696 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7697 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7698 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7699 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7700 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7701 { } /* end */
7702};
7703
7704/*
Kailang Yang272a5272007-05-14 11:00:38 +02007705 * 6ch mode
7706 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007707static const struct hda_verb alc882_3ST_ch6_init[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007708 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7709 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7710 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7711 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7712 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7713 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7714 { } /* end */
7715};
7716
Takashi Iwaia9111322011-05-02 11:30:18 +02007717static const struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007718 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007719 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007720 { 6, alc882_3ST_ch6_init },
7721};
7722
Takashi Iwai49535502009-06-30 15:28:30 +02007723#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7724
Kailang Yang272a5272007-05-14 11:00:38 +02007725/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307726 * 2ch mode
7727 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007728static const struct hda_verb alc883_3ST_ch2_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307729 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7730 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7731 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7732 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7733 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7734 { } /* end */
7735};
7736
7737/*
7738 * 4ch mode
7739 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007740static const struct hda_verb alc883_3ST_ch4_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307741 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7742 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7743 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7744 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7745 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7746 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7747 { } /* end */
7748};
7749
7750/*
7751 * 6ch mode
7752 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007753static const struct hda_verb alc883_3ST_ch6_clevo_init[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307754 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7755 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7756 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7757 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7758 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7759 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7760 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7761 { } /* end */
7762};
7763
Takashi Iwaia9111322011-05-02 11:30:18 +02007764static const struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307765 { 2, alc883_3ST_ch2_clevo_init },
7766 { 4, alc883_3ST_ch4_clevo_init },
7767 { 6, alc883_3ST_ch6_clevo_init },
7768};
7769
7770
7771/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007772 * 6ch mode
7773 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007774static const struct hda_verb alc882_sixstack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007775 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7776 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7777 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7778 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7779 { } /* end */
7780};
7781
7782/*
7783 * 8ch mode
7784 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007785static const struct hda_verb alc882_sixstack_ch8_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007786 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7787 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7788 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7789 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7790 { } /* end */
7791};
7792
Takashi Iwaia9111322011-05-02 11:30:18 +02007793static const struct hda_channel_mode alc882_sixstack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01007794 { 6, alc882_sixstack_ch6_init },
7795 { 8, alc882_sixstack_ch8_init },
7796};
7797
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007798
7799/* Macbook Air 2,1 */
7800
Takashi Iwaia9111322011-05-02 11:30:18 +02007801static const struct hda_channel_mode alc885_mba21_ch_modes[1] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007802 { 2, NULL },
7803};
7804
Takashi Iwai87350ad2007-08-16 18:19:38 +02007805/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007806 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007807 */
7808
7809/*
7810 * 2ch mode
7811 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007812static const struct hda_verb alc885_mbp_ch2_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007813 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7814 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7815 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7816 { } /* end */
7817};
7818
7819/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007820 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007821 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007822static const struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007823 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7824 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7825 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7826 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7827 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7828 { } /* end */
7829};
7830
Takashi Iwaia9111322011-05-02 11:30:18 +02007831static const struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007832 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007833 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007834};
7835
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007836/*
7837 * 2ch
7838 * Speakers/Woofer/HP = Front
7839 * LineIn = Input
7840 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007841static const struct hda_verb alc885_mb5_ch2_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007842 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7843 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7844 { } /* end */
7845};
7846
7847/*
7848 * 6ch mode
7849 * Speakers/HP = Front
7850 * Woofer = LFE
7851 * LineIn = Surround
7852 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007853static const struct hda_verb alc885_mb5_ch6_init[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007854 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7855 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7856 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7857 { } /* end */
7858};
7859
Takashi Iwaia9111322011-05-02 11:30:18 +02007860static const struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007861 { 2, alc885_mb5_ch2_init },
7862 { 6, alc885_mb5_ch6_init },
7863};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007864
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007865#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02007866
7867/*
7868 * 2ch mode
7869 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007870static const struct hda_verb alc883_4ST_ch2_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007871 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7872 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7873 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7874 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7875 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7876 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7877 { } /* end */
7878};
7879
7880/*
7881 * 4ch mode
7882 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007883static const struct hda_verb alc883_4ST_ch4_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007884 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7885 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7886 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7887 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7888 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7889 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7890 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7891 { } /* end */
7892};
7893
7894/*
7895 * 6ch mode
7896 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007897static const struct hda_verb alc883_4ST_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007898 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7899 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7900 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7901 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7902 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7903 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7904 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7905 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7906 { } /* end */
7907};
7908
7909/*
7910 * 8ch mode
7911 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007912static const struct hda_verb alc883_4ST_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007913 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7914 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7915 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7916 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7917 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7918 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7919 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7920 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7921 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7922 { } /* end */
7923};
7924
Takashi Iwaia9111322011-05-02 11:30:18 +02007925static const struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007926 { 2, alc883_4ST_ch2_init },
7927 { 4, alc883_4ST_ch4_init },
7928 { 6, alc883_4ST_ch6_init },
7929 { 8, alc883_4ST_ch8_init },
7930};
7931
7932
7933/*
7934 * 2ch mode
7935 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007936static const struct hda_verb alc883_3ST_ch2_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007937 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7938 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7939 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7940 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7941 { } /* end */
7942};
7943
7944/*
7945 * 4ch mode
7946 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007947static const struct hda_verb alc883_3ST_ch4_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007948 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7949 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7950 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7951 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7952 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7953 { } /* end */
7954};
7955
7956/*
7957 * 6ch mode
7958 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007959static const struct hda_verb alc883_3ST_ch6_intel_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007960 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7961 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7962 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7963 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7964 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7965 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7966 { } /* end */
7967};
7968
Takashi Iwaia9111322011-05-02 11:30:18 +02007969static const struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
Takashi Iwai49535502009-06-30 15:28:30 +02007970 { 2, alc883_3ST_ch2_intel_init },
7971 { 4, alc883_3ST_ch4_intel_init },
7972 { 6, alc883_3ST_ch6_intel_init },
7973};
7974
7975/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007976 * 2ch mode
7977 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007978static const struct hda_verb alc889_ch2_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007979 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7980 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7981 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7982 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7983 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7984 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7985 { } /* end */
7986};
7987
7988/*
Takashi Iwai49535502009-06-30 15:28:30 +02007989 * 6ch mode
7990 */
Takashi Iwaia9111322011-05-02 11:30:18 +02007991static const struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007992 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7993 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7994 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7995 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7996 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007997 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7998 { } /* end */
7999};
8000
8001/*
8002 * 8ch mode
8003 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008004static const struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008005 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
8006 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
8007 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
8008 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
8009 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008010 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8011 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008012 { } /* end */
8013};
8014
Takashi Iwaia9111322011-05-02 11:30:18 +02008015static const struct hda_channel_mode alc889_8ch_intel_modes[3] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08008016 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008017 { 6, alc889_ch6_intel_init },
8018 { 8, alc889_ch8_intel_init },
8019};
8020
8021/*
8022 * 6ch mode
8023 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008024static const struct hda_verb alc883_sixstack_ch6_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008025 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
8026 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8027 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8028 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8029 { } /* end */
8030};
8031
8032/*
8033 * 8ch mode
8034 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008035static const struct hda_verb alc883_sixstack_ch8_init[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008036 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8037 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8038 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8039 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
8040 { } /* end */
8041};
8042
Takashi Iwaia9111322011-05-02 11:30:18 +02008043static const struct hda_channel_mode alc883_sixstack_modes[2] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008044 { 6, alc883_sixstack_ch6_init },
8045 { 8, alc883_sixstack_ch8_init },
8046};
8047
8048
Linus Torvalds1da177e2005-04-16 15:20:36 -07008049/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
8050 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
8051 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008052static const struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02008053 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008054 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008055 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008056 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008057 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8058 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008059 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8060 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02008061 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01008062 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008063 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8064 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8065 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8066 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8067 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8068 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008069 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008070 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8071 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008072 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008073 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07008074 { } /* end */
8075};
8076
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008077/* Macbook Air 2,1 same control for HP and internal Speaker */
8078
Takashi Iwaia9111322011-05-02 11:30:18 +02008079static const struct snd_kcontrol_new alc885_mba21_mixer[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008080 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8081 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
8082 { }
8083};
8084
8085
Takashi Iwaia9111322011-05-02 11:30:18 +02008086static const struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008087 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8088 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
8089 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8090 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
8091 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01008092 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8093 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008094 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
8095 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008096 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
8097 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02008098 { } /* end */
8099};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008100
Takashi Iwaia9111322011-05-02 11:30:18 +02008101static const struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008102 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8103 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8104 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8105 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8106 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8107 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10308108 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8109 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09308110 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8111 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008112 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
8113 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008114 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
8115 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008116 { } /* end */
8117};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008118
Takashi Iwaia9111322011-05-02 11:30:18 +02008119static const struct snd_kcontrol_new alc885_macmini3_mixer[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008120 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8121 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
8122 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
8123 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
8124 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
8125 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
8126 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
8127 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
8128 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
8129 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008130 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008131 { } /* end */
8132};
8133
Takashi Iwaia9111322011-05-02 11:30:18 +02008134static const struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008135 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8136 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008137 { } /* end */
8138};
8139
8140
Takashi Iwaia9111322011-05-02 11:30:18 +02008141static const struct snd_kcontrol_new alc882_w2jc_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +02008142 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8143 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8144 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8145 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8146 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8147 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8148 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008149 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008150 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02008151 { } /* end */
8152};
8153
Takashi Iwaia9111322011-05-02 11:30:18 +02008154static const struct snd_kcontrol_new alc882_targa_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008155 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8156 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8157 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8158 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8159 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8160 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8161 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8162 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8163 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008164 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008165 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
8166 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008167 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008168 { } /* end */
8169};
8170
8171/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8172 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8173 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008174static const struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008175 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8176 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8177 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8178 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8179 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8180 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8181 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8182 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8183 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8184 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8185 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8186 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008187 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008188 { } /* end */
8189};
8190
Takashi Iwaia9111322011-05-02 11:30:18 +02008191static const struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008192 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8193 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8194 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8195 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8196 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8197 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8198 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8199 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008200 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008201 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008202 { } /* end */
8203};
8204
Takashi Iwaia9111322011-05-02 11:30:18 +02008205static const struct snd_kcontrol_new alc882_chmode_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008206 {
8207 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8208 .name = "Channel Mode",
8209 .info = alc_ch_mode_info,
8210 .get = alc_ch_mode_get,
8211 .put = alc_ch_mode_put,
8212 },
8213 { } /* end */
8214};
8215
Takashi Iwaia9111322011-05-02 11:30:18 +02008216static const struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008217 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008218 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8219 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008220 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008221 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8222 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008223 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008224 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8225 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008227 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8228 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008229
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008230 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008231 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008232 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008234 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008235 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008236 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008237 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008238 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008239 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008240 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008242 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008243 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008244 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008245 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008246 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008247 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008248 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8249 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008250 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008251 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8252 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008253 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008254 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8255 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8256 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8257 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8258 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008259 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008260 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008261
8262 /* FIXME: use matrix-type input source selection */
8263 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008264 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008265 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008266 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008267 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008268 /* ADC2: mute amp left and right */
8269 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008270 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008271 /* ADC3: mute amp left and right */
8272 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008273 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008274
8275 { }
8276};
8277
Takashi Iwaia9111322011-05-02 11:30:18 +02008278static const struct hda_verb alc882_adc1_init_verbs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02008279 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8280 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8281 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8282 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8283 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8284 /* ADC1: mute amp left and right */
8285 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8286 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8287 { }
8288};
8289
Takashi Iwaia9111322011-05-02 11:30:18 +02008290static const struct hda_verb alc882_eapd_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008291 /* change to EAPD mode */
8292 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008293 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008294 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008295};
8296
Takashi Iwaia9111322011-05-02 11:30:18 +02008297static const struct hda_verb alc889_eapd_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008298 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8299 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8300 { }
8301};
8302
Takashi Iwaia9111322011-05-02 11:30:18 +02008303static const struct hda_verb alc_hp15_unsol_verbs[] = {
Wu Fengguang6732bd02009-07-30 09:19:14 +02008304 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8305 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8306 {}
8307};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008308
Takashi Iwaia9111322011-05-02 11:30:18 +02008309static const struct hda_verb alc885_init_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008310 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008311 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8312 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008313 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008314 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8315 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008316 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008317 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8318 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008319 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008320 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8321 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008322
8323 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008324 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008325 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8326 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8327 /* Front Pin: output 0 (0x0c) */
8328 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8329 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8330 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8331 /* Rear Pin: output 1 (0x0d) */
8332 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8333 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8334 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8335 /* CLFE Pin: output 2 (0x0e) */
8336 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8337 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8338 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8339 /* Side Pin: output 3 (0x0f) */
8340 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8341 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8342 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8343 /* Mic (rear) pin: input vref at 80% */
8344 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8345 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8346 /* Front Mic pin: input vref at 80% */
8347 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8348 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8349 /* Line In pin: input */
8350 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8351 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8352
8353 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8354 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008355 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008356 /* Input mixer2 */
8357 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008358 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008359 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008360 /* ADC2: mute amp left and right */
8361 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8362 /* ADC3: mute amp left and right */
8363 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8364
8365 { }
8366};
8367
Takashi Iwaia9111322011-05-02 11:30:18 +02008368static const struct hda_verb alc885_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008369 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8370 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8371 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8372 { }
8373};
8374
8375
8376/* Unmute Selector 24h and set the default input to front mic */
Takashi Iwaia9111322011-05-02 11:30:18 +02008377static const struct hda_verb alc889_init_input_verbs[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008378 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8379 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8380 { }
8381};
8382
8383
Takashi Iwai49535502009-06-30 15:28:30 +02008384#define alc883_init_verbs alc882_base_init_verbs
8385
Tobin Davis9102cd12006-12-15 10:02:12 +01008386/* Mac Pro test */
Takashi Iwaia9111322011-05-02 11:30:18 +02008387static const struct snd_kcontrol_new alc882_macpro_mixer[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008388 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8389 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8390 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8391 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8392 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008393 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008394 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8395 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008396 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008397 { } /* end */
8398};
8399
Takashi Iwaia9111322011-05-02 11:30:18 +02008400static const struct hda_verb alc882_macpro_init_verbs[] = {
Tobin Davis9102cd12006-12-15 10:02:12 +01008401 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8402 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8403 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8404 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8405 /* Front Pin: output 0 (0x0c) */
8406 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8407 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8408 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8409 /* Front Mic pin: input vref at 80% */
8410 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8411 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8412 /* Speaker: output */
8413 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8414 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8415 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8416 /* Headphone output (output 0 - 0x0c) */
8417 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8418 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8419 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8420
8421 /* FIXME: use matrix-type input source selection */
8422 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8423 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8424 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8425 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8426 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8427 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8428 /* Input mixer2 */
8429 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8430 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8431 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8432 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8433 /* Input mixer3 */
8434 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8435 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8436 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8437 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8438 /* ADC1: mute amp left and right */
8439 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8440 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8441 /* ADC2: mute amp left and right */
8442 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8443 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8444 /* ADC3: mute amp left and right */
8445 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8446 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8447
8448 { }
8449};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008450
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008451/* Macbook 5,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008452static const struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008453 /* DACs */
8454 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8455 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8456 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8457 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008458 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008459 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8460 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8461 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008462 /* Surround mixer */
8463 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8464 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8465 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8466 /* LFE mixer */
8467 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8468 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8469 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8470 /* HP mixer */
8471 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8472 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8473 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8474 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008475 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8476 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008477 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8478 /* LFE Pin (0x0e) */
8479 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8480 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8481 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8482 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008483 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8484 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008485 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308486 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008487 /* Front Mic pin: input vref at 80% */
8488 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8489 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8490 /* Line In pin */
8491 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8492 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8493
Alex Murrayb8f171e2010-06-14 12:08:43 +09308494 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8495 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8496 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008497 { }
8498};
8499
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008500/* Macmini 3,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008501static const struct hda_verb alc885_macmini3_init_verbs[] = {
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008502 /* DACs */
8503 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8504 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8505 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8506 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8507 /* Front mixer */
8508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8510 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8511 /* Surround mixer */
8512 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8513 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8514 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8515 /* LFE mixer */
8516 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8517 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8518 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8519 /* HP mixer */
8520 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8521 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8522 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8523 /* Front Pin (0x0c) */
8524 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8525 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8526 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8527 /* LFE Pin (0x0e) */
8528 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8529 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8530 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8531 /* HP Pin (0x0f) */
8532 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8533 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8534 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8535 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8536 /* Line In pin */
8537 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8538 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8539
8540 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8541 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8542 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8543 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8544 { }
8545};
8546
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008547
Takashi Iwaia9111322011-05-02 11:30:18 +02008548static const struct hda_verb alc885_mba21_init_verbs[] = {
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008549 /*Internal and HP Speaker Mixer*/
8550 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8551 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8552 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8553 /*Internal Speaker Pin (0x0c)*/
8554 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8555 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8556 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8557 /* HP Pin: output 0 (0x0e) */
8558 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8559 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8560 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8561 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8562 /* Line in (is hp when jack connected)*/
8563 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8564 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8565
8566 { }
8567 };
8568
8569
Takashi Iwai87350ad2007-08-16 18:19:38 +02008570/* Macbook Pro rev3 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008571static const struct hda_verb alc885_mbp3_init_verbs[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02008572 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8573 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8574 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8575 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8576 /* Rear mixer */
8577 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8578 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8579 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008580 /* HP mixer */
8581 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8582 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8583 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008584 /* Front Pin: output 0 (0x0c) */
8585 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8586 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8587 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008588 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008589 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008590 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8591 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008592 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8593 /* Mic (rear) pin: input vref at 80% */
8594 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8595 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8596 /* Front Mic pin: input vref at 80% */
8597 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8598 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8599 /* Line In pin: use output 1 when in LineOut mode */
8600 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8601 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8602 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8603
8604 /* FIXME: use matrix-type input source selection */
8605 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8606 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8607 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8608 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8609 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8610 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8611 /* Input mixer2 */
8612 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8613 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8614 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8615 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8616 /* Input mixer3 */
8617 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8618 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8621 /* ADC1: mute amp left and right */
8622 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8623 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8624 /* ADC2: mute amp left and right */
8625 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8626 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8627 /* ADC3: mute amp left and right */
8628 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8629 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8630
8631 { }
8632};
8633
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008634/* iMac 9,1 */
Takashi Iwaia9111322011-05-02 11:30:18 +02008635static const struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008636 /* Internal Speaker Pin (0x0c) */
8637 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8638 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8639 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8640 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8641 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8642 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8643 /* HP Pin: Rear */
8644 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8645 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8646 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8647 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8648 /* Line in Rear */
8649 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8650 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8651 /* Front Mic pin: input vref at 80% */
8652 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8653 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008654 /* Rear mixer */
8655 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8656 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8657 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008658 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8659 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8660 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8661 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8662 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008663 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8664 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8665 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8666 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008667 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008668 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8669 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8670 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8671 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008672 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008673 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8674 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8675 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8676 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008677 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008678 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8679 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008680 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008681 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8682 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008683 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008684 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8685 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008686 { }
8687};
8688
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008689/* iMac 24 mixer. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008690static const struct snd_kcontrol_new alc885_imac24_mixer[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008691 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8692 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8693 { } /* end */
8694};
8695
8696/* iMac 24 init verbs. */
Takashi Iwaia9111322011-05-02 11:30:18 +02008697static const struct hda_verb alc885_imac24_init_verbs[] = {
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008698 /* Internal speakers: output 0 (0x0c) */
8699 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8700 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8701 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8702 /* Internal speakers: output 0 (0x0c) */
8703 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8704 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8705 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8706 /* Headphone: output 0 (0x0c) */
8707 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8708 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8709 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8710 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8711 /* Front Mic: input vref at 80% */
8712 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8713 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8714 { }
8715};
8716
8717/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008718static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008719{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008720 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008721
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008722 spec->autocfg.hp_pins[0] = 0x14;
8723 spec->autocfg.speaker_pins[0] = 0x18;
8724 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008725 spec->automute = 1;
8726 spec->automute_mode = ALC_AUTOMUTE_AMP;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008727}
8728
Takashi Iwai9d54f082010-02-22 08:34:40 +01008729#define alc885_mb5_setup alc885_imac24_setup
8730#define alc885_macmini3_setup alc885_imac24_setup
8731
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008732/* Macbook Air 2,1 */
8733static void alc885_mba21_setup(struct hda_codec *codec)
8734{
8735 struct alc_spec *spec = codec->spec;
8736
8737 spec->autocfg.hp_pins[0] = 0x14;
8738 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02008739 spec->automute = 1;
8740 spec->automute_mode = ALC_AUTOMUTE_AMP;
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008741}
8742
8743
8744
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008745static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008746{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008747 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008748
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008749 spec->autocfg.hp_pins[0] = 0x15;
8750 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02008751 spec->automute = 1;
8752 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008753}
8754
Takashi Iwai9d54f082010-02-22 08:34:40 +01008755static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308756{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008757 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308758
Takashi Iwai9d54f082010-02-22 08:34:40 +01008759 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008760 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008761 spec->autocfg.speaker_pins[1] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02008762 spec->automute = 1;
8763 spec->automute_mode = ALC_AUTOMUTE_AMP;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008764}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008765
Takashi Iwaia9111322011-05-02 11:30:18 +02008766static const struct hda_verb alc882_targa_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008767 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8768 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8769
8770 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8771 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008772
Kailang Yang272a5272007-05-14 11:00:38 +02008773 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8774 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8775 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8776
8777 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008778 { } /* end */
8779};
8780
8781/* toggle speaker-output according to the hp-jack state */
8782static void alc882_targa_automute(struct hda_codec *codec)
8783{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008784 struct alc_spec *spec = codec->spec;
Takashi Iwaid922b512011-04-28 12:18:53 +02008785 alc_hp_automute(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008786 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008787 spec->jack_present ? 1 : 3);
8788}
8789
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008790static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008791{
8792 struct alc_spec *spec = codec->spec;
8793
8794 spec->autocfg.hp_pins[0] = 0x14;
8795 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02008796 spec->automute = 1;
8797 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02008798}
8799
8800static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8801{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008802 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008803 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008804}
8805
Takashi Iwaia9111322011-05-02 11:30:18 +02008806static const struct hda_verb alc882_asus_a7j_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02008807 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8808 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8809
8810 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8811 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8812 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008813
Kailang Yang272a5272007-05-14 11:00:38 +02008814 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8815 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8816 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8817
8818 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8819 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8820 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8821 { } /* end */
8822};
8823
Takashi Iwaia9111322011-05-02 11:30:18 +02008824static const struct hda_verb alc882_asus_a7m_verbs[] = {
Takashi Iwai914759b2007-09-06 14:52:04 +02008825 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8826 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8827
8828 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8829 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8830 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008831
Takashi Iwai914759b2007-09-06 14:52:04 +02008832 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8833 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8834 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8835
8836 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8837 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8838 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8839 { } /* end */
8840};
8841
Tobin Davis9102cd12006-12-15 10:02:12 +01008842static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8843{
8844 unsigned int gpiostate, gpiomask, gpiodir;
8845
8846 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8847 AC_VERB_GET_GPIO_DATA, 0);
8848
8849 if (!muted)
8850 gpiostate |= (1 << pin);
8851 else
8852 gpiostate &= ~(1 << pin);
8853
8854 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8855 AC_VERB_GET_GPIO_MASK, 0);
8856 gpiomask |= (1 << pin);
8857
8858 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8859 AC_VERB_GET_GPIO_DIRECTION, 0);
8860 gpiodir |= (1 << pin);
8861
8862
8863 snd_hda_codec_write(codec, codec->afg, 0,
8864 AC_VERB_SET_GPIO_MASK, gpiomask);
8865 snd_hda_codec_write(codec, codec->afg, 0,
8866 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8867
8868 msleep(1);
8869
8870 snd_hda_codec_write(codec, codec->afg, 0,
8871 AC_VERB_SET_GPIO_DATA, gpiostate);
8872}
8873
Takashi Iwai7debbe52007-08-16 15:01:03 +02008874/* set up GPIO at initialization */
8875static void alc885_macpro_init_hook(struct hda_codec *codec)
8876{
8877 alc882_gpio_mute(codec, 0, 0);
8878 alc882_gpio_mute(codec, 1, 0);
8879}
8880
8881/* set up GPIO and update auto-muting at initialization */
8882static void alc885_imac24_init_hook(struct hda_codec *codec)
8883{
8884 alc885_macpro_init_hook(codec);
Takashi Iwaid922b512011-04-28 12:18:53 +02008885 alc_hp_automute(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008886}
8887
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008888/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008889static const struct hda_verb alc889A_mb31_ch2_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008890 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8891 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8892 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8893 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8894 { } /* end */
8895};
8896
8897/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008898static const struct hda_verb alc889A_mb31_ch4_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008899 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8900 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8901 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8902 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8903 { } /* end */
8904};
8905
8906/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008907static const struct hda_verb alc889A_mb31_ch5_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008908 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8909 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8910 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8911 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8912 { } /* end */
8913};
8914
8915/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
Takashi Iwaia9111322011-05-02 11:30:18 +02008916static const struct hda_verb alc889A_mb31_ch6_init[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008917 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8918 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8919 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8920 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8921 { } /* end */
8922};
8923
Takashi Iwaia9111322011-05-02 11:30:18 +02008924static const struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008925 { 2, alc889A_mb31_ch2_init },
8926 { 4, alc889A_mb31_ch4_init },
8927 { 5, alc889A_mb31_ch5_init },
8928 { 6, alc889A_mb31_ch6_init },
8929};
8930
Takashi Iwaia9111322011-05-02 11:30:18 +02008931static const struct hda_verb alc883_medion_eapd_verbs[] = {
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008932 /* eanable EAPD on medion laptop */
8933 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8934 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8935 { }
8936};
8937
Takashi Iwai49535502009-06-30 15:28:30 +02008938#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008939
Takashi Iwaia9111322011-05-02 11:30:18 +02008940static const struct snd_kcontrol_new alc883_mitac_mixer[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008941 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8942 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8943 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8944 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8945 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8946 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8947 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8948 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008949 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008950 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8951 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008952 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008953 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008954 { } /* end */
8955};
8956
Takashi Iwaia9111322011-05-02 11:30:18 +02008957static const struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008958 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8959 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8960 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8961 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8962 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008963 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008964 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008965 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008966 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008967 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008968 { } /* end */
8969};
8970
Takashi Iwaia9111322011-05-02 11:30:18 +02008971static const struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01008972 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8973 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8974 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8975 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8976 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008977 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008978 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008979 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008980 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008981 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008982 { } /* end */
8983};
8984
Takashi Iwaia9111322011-05-02 11:30:18 +02008985static const struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008986 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8987 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8988 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8989 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8990 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8991 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8992 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8993 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008994 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008995 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8996 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008997 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008998 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008999 { } /* end */
9000};
9001
Takashi Iwaia9111322011-05-02 11:30:18 +02009002static const struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009003 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9004 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9005 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9006 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9007 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9008 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9009 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9010 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9011 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9012 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9013 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9014 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9015 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9016 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009017 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009018 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9019 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009020 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009021 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009022 { } /* end */
9023};
9024
Takashi Iwaia9111322011-05-02 11:30:18 +02009025static const struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
Jiang zhe17bba1b2008-06-04 12:11:07 +02009026 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9027 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9028 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9029 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9030 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9031 HDA_OUTPUT),
9032 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9033 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9034 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9035 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9036 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9037 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9038 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9039 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9040 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009041 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009042 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9043 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009044 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009045 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02009046 { } /* end */
9047};
9048
Takashi Iwaia9111322011-05-02 11:30:18 +02009049static const struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009050 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9051 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9052 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9053 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9054 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
9055 HDA_OUTPUT),
9056 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9057 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9058 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9059 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9060 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
9061 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9062 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9063 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9064 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009065 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009066 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
9067 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009068 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009069 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9070 { } /* end */
9071};
9072
Takashi Iwaia9111322011-05-02 11:30:18 +02009073static const struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02009074 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009075 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009076 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009077 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009078 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9079 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02009080 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9081 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009082 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9083 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9084 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9085 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9086 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9087 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009088 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009089 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9090 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009091 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009092 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02009093 { } /* end */
9094};
9095
Takashi Iwaia9111322011-05-02 11:30:18 +02009096static const struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009097 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009098 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009099 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009100 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009101 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9102 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
9103 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
9104 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
9105 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
9106 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
9107 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9108 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9109 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9110 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9111 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009112 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009113 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009114 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009115};
Kailang Yangccc656c2006-10-17 12:32:26 +02009116
Takashi Iwaia9111322011-05-02 11:30:18 +02009117static const struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009118 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009119 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009120 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009121 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009122 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9123 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9124 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009125 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009126 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009127 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009128 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009129 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02009130 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009131};
Kailang Yangccc656c2006-10-17 12:32:26 +02009132
Takashi Iwaia9111322011-05-02 11:30:18 +02009133static const struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +02009134 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9135 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009136 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009137 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009138 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009139 { } /* end */
9140};
9141
Takashi Iwaia9111322011-05-02 11:30:18 +02009142static const struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009143 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9144 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009145 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9146 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009147 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9148 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009149 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009150 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009151 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009152};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009153
Takashi Iwaia9111322011-05-02 11:30:18 +02009154static const struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009155 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9156 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9157 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9158 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9159 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9160 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9161 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009162 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9163 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009164 { } /* end */
Kailang Yangea1fb292008-08-26 12:58:38 +02009165};
Kailang Yang272a5272007-05-14 11:00:38 +02009166
Takashi Iwaia9111322011-05-02 11:30:18 +02009167static const struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009168 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9169 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9170 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9171 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9172 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9173 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9174 { } /* end */
9175};
9176
Takashi Iwaia9111322011-05-02 11:30:18 +02009177static const struct hda_verb alc883_medion_wim2160_verbs[] = {
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009178 /* Unmute front mixer */
9179 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9180 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9181
9182 /* Set speaker pin to front mixer */
9183 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9184
9185 /* Init headphone pin */
9186 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9187 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9188 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9189 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9190
9191 { } /* end */
9192};
9193
9194/* toggle speaker-output according to the hp-jack state */
9195static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9196{
9197 struct alc_spec *spec = codec->spec;
9198
9199 spec->autocfg.hp_pins[0] = 0x1a;
9200 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009201 spec->automute = 1;
9202 spec->automute_mode = ALC_AUTOMUTE_AMP;
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009203}
9204
Takashi Iwaia9111322011-05-02 11:30:18 +02009205static const struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009206 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9207 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009208 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009209 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9210 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009211 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009212 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009213 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009214 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009215};
Tobin Davis2880a862007-08-07 11:50:26 +02009216
Takashi Iwaia9111322011-05-02 11:30:18 +02009217static const struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
Tony Vroond2fd4b02009-06-21 00:40:10 +01009218 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009219 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009220 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9221 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009222 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("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009225 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009226 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9227 { } /* end */
9228};
9229
Takashi Iwaia9111322011-05-02 11:30:18 +02009230static const struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009231 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9232 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9233 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9234 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9235 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9236 0x0d, 1, 0x0, HDA_OUTPUT),
9237 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9238 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9239 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9240 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9241 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009242 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9243 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9244 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9245 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9246 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009247 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009248 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9249 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009250 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009251 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009252 { } /* end */
9253};
9254
Takashi Iwaia9111322011-05-02 11:30:18 +02009255static const struct snd_kcontrol_new alc889A_mb31_mixer[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009256 /* Output mixers */
9257 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9258 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9259 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9260 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9261 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9262 HDA_OUTPUT),
9263 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9264 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9265 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9266 /* Output switches */
9267 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9268 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9269 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9270 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009271 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9272 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009273 /* Input mixers */
9274 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9275 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9276 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9277 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9278 { } /* end */
9279};
9280
Takashi Iwaia9111322011-05-02 11:30:18 +02009281static const struct snd_kcontrol_new alc883_vaiott_mixer[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009282 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9283 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9284 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9285 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009286 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c2009-06-05 00:47:26 +02009287 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9288 { } /* end */
9289};
9290
Takashi Iwaia9111322011-05-02 11:30:18 +02009291static const struct hda_bind_ctls alc883_bind_cap_vol = {
Kailang Yange2757d52008-08-26 13:17:46 +02009292 .ops = &snd_hda_bind_vol,
9293 .values = {
9294 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9295 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9296 0
9297 },
9298};
9299
Takashi Iwaia9111322011-05-02 11:30:18 +02009300static const struct hda_bind_ctls alc883_bind_cap_switch = {
Kailang Yange2757d52008-08-26 13:17:46 +02009301 .ops = &snd_hda_bind_sw,
9302 .values = {
9303 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9304 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9305 0
9306 },
9307};
9308
Takashi Iwaia9111322011-05-02 11:30:18 +02009309static const struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009310 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9311 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9312 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9313 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9314 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9315 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009316 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009317 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009318 { } /* end */
9319};
9320
Takashi Iwaia9111322011-05-02 11:30:18 +02009321static const struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009322 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9323 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9324 {
9325 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9326 /* .name = "Capture Source", */
9327 .name = "Input Source",
9328 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009329 .info = alc_mux_enum_info,
9330 .get = alc_mux_enum_get,
9331 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009332 },
9333 { } /* end */
9334};
9335
Takashi Iwaia9111322011-05-02 11:30:18 +02009336static const struct snd_kcontrol_new alc883_chmode_mixer[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009337 {
9338 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9339 .name = "Channel Mode",
9340 .info = alc_ch_mode_info,
9341 .get = alc_ch_mode_get,
9342 .put = alc_ch_mode_put,
9343 },
9344 { } /* end */
9345};
9346
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009347/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009348static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009349{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009350 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009351
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009352 spec->autocfg.hp_pins[0] = 0x15;
9353 spec->autocfg.speaker_pins[0] = 0x14;
9354 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009355 spec->automute = 1;
9356 spec->automute_mode = ALC_AUTOMUTE_AMP;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009357}
9358
Takashi Iwaia9111322011-05-02 11:30:18 +02009359static const struct hda_verb alc883_mitac_verbs[] = {
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009360 /* HP */
9361 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9362 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9363 /* Subwoofer */
9364 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9365 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9366
9367 /* enable unsolicited event */
9368 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9369 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9370
9371 { } /* end */
9372};
9373
Takashi Iwaia9111322011-05-02 11:30:18 +02009374static const struct hda_verb alc883_clevo_m540r_verbs[] = {
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309375 /* HP */
9376 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9377 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9378 /* Int speaker */
9379 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9380
9381 /* enable unsolicited event */
9382 /*
9383 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9384 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9385 */
9386
9387 { } /* end */
9388};
9389
Takashi Iwaia9111322011-05-02 11:30:18 +02009390static const struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009391 /* HP */
9392 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9393 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9394 /* Int speaker */
9395 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9396 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9397
9398 /* enable unsolicited event */
9399 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009400 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009401
9402 { } /* end */
9403};
9404
Takashi Iwaia9111322011-05-02 11:30:18 +02009405static const struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
Jiang zhefb97dc62008-03-06 11:07:11 +01009406 /* HP */
9407 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9408 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9409 /* Subwoofer */
9410 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9411 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9412
9413 /* enable unsolicited event */
9414 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9415
9416 { } /* end */
9417};
9418
Takashi Iwaia9111322011-05-02 11:30:18 +02009419static const struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009420 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9421 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9422
9423 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9424 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009425
David Heidelberger64a8be72009-06-08 16:15:18 +02009426/* Connect Line-Out side jack (SPDIF) to Side */
9427 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9428 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9429 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9430/* Connect Mic jack to CLFE */
9431 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9432 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9433 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9434/* Connect Line-in jack to Surround */
9435 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9436 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9437 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9438/* Connect HP out jack to Front */
9439 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9440 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9441 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009442
9443 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009444
9445 { } /* end */
9446};
9447
Takashi Iwaia9111322011-05-02 11:30:18 +02009448static const struct hda_verb alc883_lenovo_101e_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009449 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9450 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9451 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9452 { } /* end */
9453};
9454
Takashi Iwaia9111322011-05-02 11:30:18 +02009455static const struct hda_verb alc883_lenovo_nb0763_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009456 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9457 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9458 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9459 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9460 { } /* end */
9461};
9462
Takashi Iwaia9111322011-05-02 11:30:18 +02009463static const struct hda_verb alc888_lenovo_ms7195_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +02009464 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9465 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9466 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9467 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9468 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9469 { } /* end */
9470};
9471
Takashi Iwaia9111322011-05-02 11:30:18 +02009472static const struct hda_verb alc883_haier_w66_verbs[] = {
Kailang Yang189609a2007-08-20 11:31:23 +02009473 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9474 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9475
9476 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9477
9478 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9479 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9480 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9481 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9482 { } /* end */
9483};
9484
Takashi Iwaia9111322011-05-02 11:30:18 +02009485static const struct hda_verb alc888_lenovo_sky_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009486 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9487 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9488 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9489 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9490 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9491 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9492 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9493 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9494 { } /* end */
9495};
9496
Takashi Iwaia9111322011-05-02 11:30:18 +02009497static const struct hda_verb alc888_6st_dell_verbs[] = {
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009498 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9499 { }
9500};
9501
Takashi Iwaia9111322011-05-02 11:30:18 +02009502static const struct hda_verb alc883_vaiott_verbs[] = {
Guido Günther3e1647c2009-06-05 00:47:26 +02009503 /* HP */
9504 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9505 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9506
9507 /* enable unsolicited event */
9508 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9509
9510 { } /* end */
9511};
9512
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009513static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009514{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009515 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009516
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009517 spec->autocfg.hp_pins[0] = 0x1b;
9518 spec->autocfg.speaker_pins[0] = 0x14;
9519 spec->autocfg.speaker_pins[1] = 0x16;
9520 spec->autocfg.speaker_pins[2] = 0x18;
Takashi Iwaid922b512011-04-28 12:18:53 +02009521 spec->automute = 1;
9522 spec->automute_mode = ALC_AUTOMUTE_AMP;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009523}
9524
Takashi Iwaia9111322011-05-02 11:30:18 +02009525static const struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009526 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009527 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9528 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009529 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009530 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009531};
9532
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009533/*
9534 * 2ch mode
9535 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009536static const struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009537 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9538 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9539 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9540 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009541 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009542};
9543
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009544/*
9545 * 4ch mode
9546 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009547static const struct hda_verb alc888_3st_hp_4ch_init[] = {
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009548 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9549 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9550 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9551 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9552 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9553 { } /* end */
9554};
9555
9556/*
9557 * 6ch mode
9558 */
Takashi Iwaia9111322011-05-02 11:30:18 +02009559static const struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009560 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9561 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009562 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009563 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9564 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009565 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9566 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009567};
9568
Takashi Iwaia9111322011-05-02 11:30:18 +02009569static const struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009570 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009571 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009572 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009573};
9574
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009575static void alc888_lenovo_ms7195_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009576{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009577 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009578
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009579 spec->autocfg.hp_pins[0] = 0x1b;
9580 spec->autocfg.line_out_pins[0] = 0x14;
9581 spec->autocfg.speaker_pins[0] = 0x15;
9582 spec->automute = 1;
9583 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009584}
9585
Kailang Yang272a5272007-05-14 11:00:38 +02009586/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc427172010-11-29 07:42:59 +01009587static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009588{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009589 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009590
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009591 spec->autocfg.hp_pins[0] = 0x14;
9592 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009593 spec->automute = 1;
9594 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +02009595}
9596
Kailang Yangccc656c2006-10-17 12:32:26 +02009597/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009598#define alc883_targa_init_hook alc882_targa_init_hook
9599#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009600
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009601static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009602{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009603 struct alc_spec *spec = codec->spec;
9604
9605 spec->autocfg.hp_pins[0] = 0x15;
9606 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009607 spec->automute = 1;
9608 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009609}
9610
9611static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9612{
Takashi Iwaid922b512011-04-28 12:18:53 +02009613 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009614 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009615}
9616
9617static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009618 unsigned int res)
9619{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009620 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009621 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009622 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009623 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009624 default:
Takashi Iwaid922b512011-04-28 12:18:53 +02009625 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009626 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009627 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009628}
9629
Jiang zhefb97dc62008-03-06 11:07:11 +01009630/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009631static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009632{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009633 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009634
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009635 spec->autocfg.hp_pins[0] = 0x14;
9636 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +02009637 spec->automute = 1;
9638 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhefb97dc62008-03-06 11:07:11 +01009639}
9640
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009641static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009642{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009643 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009644
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009645 spec->autocfg.hp_pins[0] = 0x1b;
9646 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +02009647 spec->automute = 1;
9648 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang189609a2007-08-20 11:31:23 +02009649}
9650
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009651static void alc883_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009652{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009653 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009654
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +02009655 spec->autocfg.hp_pins[0] = 0x1b;
9656 spec->autocfg.line_out_pins[0] = 0x14;
9657 spec->autocfg.speaker_pins[0] = 0x15;
9658 spec->automute = 1;
9659 spec->detect_line = 1;
9660 spec->automute_lines = 1;
9661 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009662}
9663
Takashi Iwai676a9b52007-08-16 15:23:35 +02009664/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009665static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009666{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009667 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009668
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009669 spec->autocfg.hp_pins[0] = 0x14;
9670 spec->autocfg.speaker_pins[0] = 0x15;
9671 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwaid922b512011-04-28 12:18:53 +02009672 spec->automute = 1;
9673 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009674}
9675
Takashi Iwaia9111322011-05-02 11:30:18 +02009676static const struct hda_verb alc883_acer_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009677 /* HP Pin: output 0 (0x0c) */
9678 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9679 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9680 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9681 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009682 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9683 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009684 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009685 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9686 /* eanable EAPD on medion laptop */
9687 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9688 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009689 /* enable unsolicited event */
9690 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009691 { }
9692};
9693
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009694static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009695{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009696 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009697
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009698 spec->autocfg.hp_pins[0] = 0x1b;
9699 spec->autocfg.speaker_pins[0] = 0x14;
9700 spec->autocfg.speaker_pins[1] = 0x15;
9701 spec->autocfg.speaker_pins[2] = 0x16;
9702 spec->autocfg.speaker_pins[3] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009703 spec->automute = 1;
9704 spec->automute_mode = ALC_AUTOMUTE_AMP;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009705}
9706
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009707static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009708{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009709 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009710
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009711 spec->autocfg.hp_pins[0] = 0x1b;
9712 spec->autocfg.speaker_pins[0] = 0x14;
9713 spec->autocfg.speaker_pins[1] = 0x15;
9714 spec->autocfg.speaker_pins[2] = 0x16;
9715 spec->autocfg.speaker_pins[3] = 0x17;
9716 spec->autocfg.speaker_pins[4] = 0x1a;
Takashi Iwaid922b512011-04-28 12:18:53 +02009717 spec->automute = 1;
9718 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009719}
9720
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009721static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009722{
9723 struct alc_spec *spec = codec->spec;
9724
9725 spec->autocfg.hp_pins[0] = 0x15;
9726 spec->autocfg.speaker_pins[0] = 0x14;
9727 spec->autocfg.speaker_pins[1] = 0x17;
Takashi Iwaid922b512011-04-28 12:18:53 +02009728 spec->automute = 1;
9729 spec->automute_mode = ALC_AUTOMUTE_AMP;
Guido Günther3e1647c2009-06-05 00:47:26 +02009730}
9731
Takashi Iwaia9111322011-05-02 11:30:18 +02009732static const struct hda_verb alc888_asus_m90v_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009733 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9734 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9735 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9736 /* enable unsolicited event */
9737 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9738 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9739 { } /* end */
9740};
9741
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009742static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009743{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009744 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009745
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009746 spec->autocfg.hp_pins[0] = 0x1b;
9747 spec->autocfg.speaker_pins[0] = 0x14;
9748 spec->autocfg.speaker_pins[1] = 0x15;
9749 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai21268962011-07-07 15:01:13 +02009750 spec->ext_mic_pin = 0x18;
9751 spec->int_mic_pin = 0x19;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009752 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +02009753 spec->automute = 1;
9754 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yange2757d52008-08-26 13:17:46 +02009755}
9756
Takashi Iwaia9111322011-05-02 11:30:18 +02009757static const struct hda_verb alc888_asus_eee1601_verbs[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009758 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9759 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9760 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9761 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9762 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9763 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9764 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9765 /* enable unsolicited event */
9766 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9767 { } /* end */
9768};
9769
Kailang Yange2757d52008-08-26 13:17:46 +02009770static void alc883_eee1601_inithook(struct hda_codec *codec)
9771{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009772 struct alc_spec *spec = codec->spec;
9773
9774 spec->autocfg.hp_pins[0] = 0x14;
9775 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaid922b512011-04-28 12:18:53 +02009776 alc_hp_automute(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009777}
9778
Takashi Iwaia9111322011-05-02 11:30:18 +02009779static const struct hda_verb alc889A_mb31_verbs[] = {
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009780 /* Init rear pin (used as headphone output) */
9781 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9782 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9783 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9784 /* Init line pin (used as output in 4ch and 6ch mode) */
9785 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9786 /* Init line 2 pin (used as headphone out by default) */
9787 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9788 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9789 { } /* end */
9790};
9791
9792/* Mute speakers according to the headphone jack state */
9793static void alc889A_mb31_automute(struct hda_codec *codec)
9794{
9795 unsigned int present;
9796
9797 /* Mute only in 2ch or 4ch mode */
9798 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9799 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009800 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009801 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9802 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9803 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9804 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9805 }
9806}
9807
9808static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9809{
9810 if ((res >> 26) == ALC880_HP_EVENT)
9811 alc889A_mb31_automute(codec);
9812}
9813
Takashi Iwai49535502009-06-30 15:28:30 +02009814
Takashi Iwaicb53c622007-08-10 17:21:45 +02009815#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02009816#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009817#endif
9818
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02009819static const hda_nid_t alc883_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009820 ALC1200_DIGOUT_NID, 0,
9821};
9822
Takashi Iwai4c6d72d2011-05-02 11:30:18 +02009823static const hda_nid_t alc1200_slave_dig_outs[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009824 ALC883_DIGOUT_NID, 0,
9825};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009826
9827/*
9828 * configuration and preset
9829 */
Takashi Iwaiea734962011-01-17 11:29:34 +01009830static const char * const alc882_models[ALC882_MODEL_LAST] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009831 [ALC882_3ST_DIG] = "3stack-dig",
9832 [ALC882_6ST_DIG] = "6stack-dig",
9833 [ALC882_ARIMA] = "arima",
9834 [ALC882_W2JC] = "w2jc",
9835 [ALC882_TARGA] = "targa",
9836 [ALC882_ASUS_A7J] = "asus-a7j",
9837 [ALC882_ASUS_A7M] = "asus-a7m",
9838 [ALC885_MACPRO] = "macpro",
9839 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009840 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009841 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +02009842 [ALC885_MBP3] = "mbp3",
9843 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009844 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02009845 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009846 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9847 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02009848 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009849 [ALC883_TARGA_DIG] = "targa-dig",
9850 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009851 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009852 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009853 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009854 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009855 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009856 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009857 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009858 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009859 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009860 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009861 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009862 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9863 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009864 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009865 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009866 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009867 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009868 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309869 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009870 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009871 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009872 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009873 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009874 [ALC889A_INTEL] = "intel-alc889a",
9875 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009876 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009877 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009878 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02009879 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009880};
9881
Takashi Iwaia9111322011-05-02 11:30:18 +02009882static const struct snd_pci_quirk alc882_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +02009883 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9884
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009885 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009886 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009887 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009888 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9889 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009890 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009891 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9892 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009893 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009894 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009895 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9896 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009897 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9898 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02009899 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9900 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009901 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009902 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009903 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009904 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009905 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9906 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009907 /* default Acer -- disabled as it causes more problems.
9908 * model=auto should work fine now
9909 */
9910 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02009911
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009912 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02009913
Lucas De Marchi25985ed2011-03-30 22:57:33 -03009914 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavilion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009915 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9916 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009917 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009918 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009919 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02009920
9921 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9922 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9923 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009924 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02009925 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9926 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9927 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009928 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009929 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009930 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009931 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02009932
9933 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009934 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009935 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009936 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009937 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9938 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009939 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009940 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwaiebb47242011-05-02 10:37:29 +02009941 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009942
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009943 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9944 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9945 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009946 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009947 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +02009948 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009949 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009950 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009951 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9952 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9953 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9954 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9955 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9956 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009957 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009958 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9959 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9960 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009961 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009962 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009963 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9964 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009965 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009966 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009967 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009968 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009969 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009970 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009971 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009972 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009973 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009974
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009975 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009976 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009977 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9978 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309979 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009980 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009981 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009982 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009983 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009984 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009985 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009986 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009987 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009988 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009989 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009990 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9991 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009992 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +01009993 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009994 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009995 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009996
Jiang zhe17bba1b2008-06-04 12:11:07 +02009997 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9998 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009999 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010000 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
10001 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
10002 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -040010003 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +020010004
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010005 {}
10006};
10007
Takashi Iwai49535502009-06-30 15:28:30 +020010008/* codec SSID table for Intel Mac */
Takashi Iwaia9111322011-05-02 11:30:18 +020010009static const struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010010 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
10011 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
10012 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
10013 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
10014 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
10015 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
10016 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -040010017 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -070010018 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -070010019 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -070010020 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +020010021 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
10022 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
10023 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010024 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +020010025 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +100010026 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010027 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
10028 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +020010029 */
10030 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -050010031 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010032 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +020010033 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010034};
10035
Takashi Iwaia9111322011-05-02 11:30:18 +020010036static const struct alc_config_preset alc882_presets[] = {
Takashi Iwai49535502009-06-30 15:28:30 +020010037 [ALC882_3ST_DIG] = {
10038 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010039 .init_verbs = { alc882_base_init_verbs,
10040 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010041 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10042 .dac_nids = alc882_dac_nids,
10043 .dig_out_nid = ALC882_DIGOUT_NID,
10044 .dig_in_nid = ALC882_DIGIN_NID,
10045 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10046 .channel_mode = alc882_ch_modes,
10047 .need_dac_fix = 1,
10048 .input_mux = &alc882_capture_source,
10049 },
10050 [ALC882_6ST_DIG] = {
10051 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010052 .init_verbs = { alc882_base_init_verbs,
10053 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010054 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10055 .dac_nids = alc882_dac_nids,
10056 .dig_out_nid = ALC882_DIGOUT_NID,
10057 .dig_in_nid = ALC882_DIGIN_NID,
10058 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10059 .channel_mode = alc882_sixstack_modes,
10060 .input_mux = &alc882_capture_source,
10061 },
10062 [ALC882_ARIMA] = {
10063 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010064 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10065 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010066 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10067 .dac_nids = alc882_dac_nids,
10068 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
10069 .channel_mode = alc882_sixstack_modes,
10070 .input_mux = &alc882_capture_source,
10071 },
10072 [ALC882_W2JC] = {
10073 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010074 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10075 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +020010076 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10077 .dac_nids = alc882_dac_nids,
10078 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10079 .channel_mode = alc880_threestack_modes,
10080 .need_dac_fix = 1,
10081 .input_mux = &alc882_capture_source,
10082 .dig_out_nid = ALC882_DIGOUT_NID,
10083 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010084 [ALC885_MBA21] = {
10085 .mixers = { alc885_mba21_mixer },
10086 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
10087 .num_dacs = 2,
10088 .dac_nids = alc882_dac_nids,
10089 .channel_mode = alc885_mba21_ch_modes,
10090 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10091 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010092 .unsol_event = alc_sku_unsol_event,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010093 .setup = alc885_mba21_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010094 .init_hook = alc_hp_automute,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -080010095 },
Takashi Iwai49535502009-06-30 15:28:30 +020010096 [ALC885_MBP3] = {
10097 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
10098 .init_verbs = { alc885_mbp3_init_verbs,
10099 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010100 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +020010101 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +020010102 .hp_nid = 0x04,
10103 .channel_mode = alc885_mbp_4ch_modes,
10104 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +020010105 .input_mux = &alc882_capture_source,
10106 .dig_out_nid = ALC882_DIGOUT_NID,
10107 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010108 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010109 .setup = alc885_mbp3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010110 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010111 },
10112 [ALC885_MB5] = {
10113 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
10114 .init_verbs = { alc885_mb5_init_verbs,
10115 alc880_gpio1_init_verbs },
10116 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10117 .dac_nids = alc882_dac_nids,
10118 .channel_mode = alc885_mb5_6ch_modes,
10119 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10120 .input_mux = &mb5_capture_source,
10121 .dig_out_nid = ALC882_DIGOUT_NID,
10122 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010123 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010124 .setup = alc885_mb5_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010125 .init_hook = alc_hp_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010126 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010127 [ALC885_MACMINI3] = {
10128 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10129 .init_verbs = { alc885_macmini3_init_verbs,
10130 alc880_gpio1_init_verbs },
10131 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10132 .dac_nids = alc882_dac_nids,
10133 .channel_mode = alc885_macmini3_6ch_modes,
10134 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10135 .input_mux = &macmini3_capture_source,
10136 .dig_out_nid = ALC882_DIGOUT_NID,
10137 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010138 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010139 .setup = alc885_macmini3_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010140 .init_hook = alc_hp_automute,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010141 },
Takashi Iwai49535502009-06-30 15:28:30 +020010142 [ALC885_MACPRO] = {
10143 .mixers = { alc882_macpro_mixer },
10144 .init_verbs = { alc882_macpro_init_verbs },
10145 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10146 .dac_nids = alc882_dac_nids,
10147 .dig_out_nid = ALC882_DIGOUT_NID,
10148 .dig_in_nid = ALC882_DIGIN_NID,
10149 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10150 .channel_mode = alc882_ch_modes,
10151 .input_mux = &alc882_capture_source,
10152 .init_hook = alc885_macpro_init_hook,
10153 },
10154 [ALC885_IMAC24] = {
10155 .mixers = { alc885_imac24_mixer },
10156 .init_verbs = { alc885_imac24_init_verbs },
10157 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10158 .dac_nids = alc882_dac_nids,
10159 .dig_out_nid = ALC882_DIGOUT_NID,
10160 .dig_in_nid = ALC882_DIGIN_NID,
10161 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10162 .channel_mode = alc882_ch_modes,
10163 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010164 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010165 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +020010166 .init_hook = alc885_imac24_init_hook,
10167 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010168 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010169 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010170 .init_verbs = { alc885_imac91_init_verbs,
10171 alc880_gpio1_init_verbs },
10172 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10173 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010174 .channel_mode = alc885_mba21_ch_modes,
10175 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10176 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010177 .dig_out_nid = ALC882_DIGOUT_NID,
10178 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwaid922b512011-04-28 12:18:53 +020010179 .unsol_event = alc_sku_unsol_event,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010180 .setup = alc885_imac91_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010181 .init_hook = alc_hp_automute,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010182 },
Takashi Iwai49535502009-06-30 15:28:30 +020010183 [ALC882_TARGA] = {
10184 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010185 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010186 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010187 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10188 .dac_nids = alc882_dac_nids,
10189 .dig_out_nid = ALC882_DIGOUT_NID,
10190 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10191 .adc_nids = alc882_adc_nids,
10192 .capsrc_nids = alc882_capsrc_nids,
10193 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10194 .channel_mode = alc882_3ST_6ch_modes,
10195 .need_dac_fix = 1,
10196 .input_mux = &alc882_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010197 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010198 .setup = alc882_targa_setup,
10199 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010200 },
10201 [ALC882_ASUS_A7J] = {
10202 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010203 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10204 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010205 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10206 .dac_nids = alc882_dac_nids,
10207 .dig_out_nid = ALC882_DIGOUT_NID,
10208 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10209 .adc_nids = alc882_adc_nids,
10210 .capsrc_nids = alc882_capsrc_nids,
10211 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10212 .channel_mode = alc882_3ST_6ch_modes,
10213 .need_dac_fix = 1,
10214 .input_mux = &alc882_capture_source,
10215 },
10216 [ALC882_ASUS_A7M] = {
10217 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010218 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10219 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +020010220 alc882_asus_a7m_verbs },
10221 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10222 .dac_nids = alc882_dac_nids,
10223 .dig_out_nid = ALC882_DIGOUT_NID,
10224 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10225 .channel_mode = alc880_threestack_modes,
10226 .need_dac_fix = 1,
10227 .input_mux = &alc882_capture_source,
10228 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010229 [ALC883_3ST_2ch_DIG] = {
10230 .mixers = { alc883_3ST_2ch_mixer },
10231 .init_verbs = { alc883_init_verbs },
10232 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10233 .dac_nids = alc883_dac_nids,
10234 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010235 .dig_in_nid = ALC883_DIGIN_NID,
10236 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10237 .channel_mode = alc883_3ST_2ch_modes,
10238 .input_mux = &alc883_capture_source,
10239 },
10240 [ALC883_3ST_6ch_DIG] = {
10241 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10242 .init_verbs = { alc883_init_verbs },
10243 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10244 .dac_nids = alc883_dac_nids,
10245 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010246 .dig_in_nid = ALC883_DIGIN_NID,
10247 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10248 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010249 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010250 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010251 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010252 [ALC883_3ST_6ch] = {
10253 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10254 .init_verbs = { alc883_init_verbs },
10255 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10256 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010257 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10258 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010259 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010260 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010261 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010262 [ALC883_3ST_6ch_INTEL] = {
10263 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10264 .init_verbs = { alc883_init_verbs },
10265 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10266 .dac_nids = alc883_dac_nids,
10267 .dig_out_nid = ALC883_DIGOUT_NID,
10268 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010269 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010270 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10271 .channel_mode = alc883_3ST_6ch_intel_modes,
10272 .need_dac_fix = 1,
10273 .input_mux = &alc883_3stack_6ch_intel,
10274 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010275 [ALC889A_INTEL] = {
10276 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010277 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10278 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010279 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10280 .dac_nids = alc883_dac_nids,
10281 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10282 .adc_nids = alc889_adc_nids,
10283 .dig_out_nid = ALC883_DIGOUT_NID,
10284 .dig_in_nid = ALC883_DIGIN_NID,
10285 .slave_dig_outs = alc883_slave_dig_outs,
10286 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10287 .channel_mode = alc889_8ch_intel_modes,
10288 .capsrc_nids = alc889_capsrc_nids,
10289 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010290 .setup = alc889_automute_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010291 .init_hook = alc_hp_automute,
10292 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010293 .need_dac_fix = 1,
10294 },
10295 [ALC889_INTEL] = {
10296 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10297 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010298 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010299 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10300 .dac_nids = alc883_dac_nids,
10301 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10302 .adc_nids = alc889_adc_nids,
10303 .dig_out_nid = ALC883_DIGOUT_NID,
10304 .dig_in_nid = ALC883_DIGIN_NID,
10305 .slave_dig_outs = alc883_slave_dig_outs,
10306 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10307 .channel_mode = alc889_8ch_intel_modes,
10308 .capsrc_nids = alc889_capsrc_nids,
10309 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010310 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010311 .init_hook = alc889_intel_init_hook,
Takashi Iwaid922b512011-04-28 12:18:53 +020010312 .unsol_event = alc_sku_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010313 .need_dac_fix = 1,
10314 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010315 [ALC883_6ST_DIG] = {
10316 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10317 .init_verbs = { alc883_init_verbs },
10318 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10319 .dac_nids = alc883_dac_nids,
10320 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010321 .dig_in_nid = ALC883_DIGIN_NID,
10322 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10323 .channel_mode = alc883_sixstack_modes,
10324 .input_mux = &alc883_capture_source,
10325 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010326 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010327 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010328 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10329 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010330 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10331 .dac_nids = alc883_dac_nids,
10332 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010333 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10334 .channel_mode = alc883_3ST_6ch_modes,
10335 .need_dac_fix = 1,
10336 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010337 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010338 .setup = alc882_targa_setup,
10339 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010340 },
10341 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010342 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010343 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10344 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010345 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10346 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010347 .adc_nids = alc883_adc_nids_alt,
10348 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010349 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010350 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010351 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10352 .channel_mode = alc883_3ST_2ch_modes,
10353 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010354 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010355 .setup = alc882_targa_setup,
10356 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010357 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010358 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010359 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10360 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010361 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010362 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010363 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10364 .dac_nids = alc883_dac_nids,
10365 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10366 .adc_nids = alc883_adc_nids_rev,
10367 .capsrc_nids = alc883_capsrc_nids_rev,
10368 .dig_out_nid = ALC883_DIGOUT_NID,
10369 .dig_in_nid = ALC883_DIGIN_NID,
10370 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10371 .channel_mode = alc883_4ST_8ch_modes,
10372 .need_dac_fix = 1,
10373 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010374 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010375 .setup = alc882_targa_setup,
10376 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010377 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010378 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010379 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010380 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10381 * and the headphone jack. Turn this on and rely on the
10382 * standard mute methods whenever the user wants to turn
10383 * these outputs off.
10384 */
10385 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10386 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10387 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010388 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10389 .channel_mode = alc883_3ST_2ch_modes,
10390 .input_mux = &alc883_capture_source,
10391 },
Tobin Davis2880a862007-08-07 11:50:26 +020010392 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010393 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010394 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010395 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10396 .dac_nids = alc883_dac_nids,
10397 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010398 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10399 .channel_mode = alc883_3ST_2ch_modes,
10400 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010401 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010402 .setup = alc883_acer_aspire_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010403 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010404 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010405 [ALC888_ACER_ASPIRE_4930G] = {
Łukasz Wojniłowicz460c92f2011-02-07 13:13:27 +010010406 .mixers = { alc888_acer_aspire_4930g_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010407 alc883_chmode_mixer },
10408 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10409 alc888_acer_aspire_4930g_verbs },
10410 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10411 .dac_nids = alc883_dac_nids,
10412 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10413 .adc_nids = alc883_adc_nids_rev,
10414 .capsrc_nids = alc883_capsrc_nids_rev,
10415 .dig_out_nid = ALC883_DIGOUT_NID,
10416 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10417 .channel_mode = alc883_3ST_6ch_modes,
10418 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010419 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010420 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010421 ARRAY_SIZE(alc888_2_capture_sources),
10422 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010423 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010424 .setup = alc888_acer_aspire_4930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010425 .init_hook = alc_hp_automute,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010426 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010427 [ALC888_ACER_ASPIRE_6530G] = {
10428 .mixers = { alc888_acer_aspire_6530_mixer },
10429 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10430 alc888_acer_aspire_6530g_verbs },
10431 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10432 .dac_nids = alc883_dac_nids,
10433 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10434 .adc_nids = alc883_adc_nids_rev,
10435 .capsrc_nids = alc883_capsrc_nids_rev,
10436 .dig_out_nid = ALC883_DIGOUT_NID,
10437 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10438 .channel_mode = alc883_3ST_2ch_modes,
10439 .num_mux_defs =
10440 ARRAY_SIZE(alc888_2_capture_sources),
10441 .input_mux = alc888_acer_aspire_6530_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010442 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010443 .setup = alc888_acer_aspire_6530g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010444 .init_hook = alc_hp_automute,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010445 },
Hector Martin3b315d72009-06-02 10:54:19 +020010446 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010447 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010448 alc883_chmode_mixer },
10449 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010450 alc889_acer_aspire_8930g_verbs,
10451 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010452 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10453 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010454 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10455 .adc_nids = alc889_adc_nids,
10456 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010457 .dig_out_nid = ALC883_DIGOUT_NID,
10458 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10459 .channel_mode = alc883_3ST_6ch_modes,
10460 .need_dac_fix = 1,
10461 .const_channel_count = 6,
10462 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010463 ARRAY_SIZE(alc889_capture_sources),
10464 .input_mux = alc889_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010465 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010466 .setup = alc889_acer_aspire_8930g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010467 .init_hook = alc_hp_automute,
Hector Martinf5de24b2009-12-20 22:51:31 +010010468#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010469 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010470#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010471 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010472 [ALC888_ACER_ASPIRE_7730G] = {
10473 .mixers = { alc883_3ST_6ch_mixer,
10474 alc883_chmode_mixer },
10475 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10476 alc888_acer_aspire_7730G_verbs },
10477 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10478 .dac_nids = alc883_dac_nids,
10479 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10480 .adc_nids = alc883_adc_nids_rev,
10481 .capsrc_nids = alc883_capsrc_nids_rev,
10482 .dig_out_nid = ALC883_DIGOUT_NID,
10483 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10484 .channel_mode = alc883_3ST_6ch_modes,
10485 .need_dac_fix = 1,
10486 .const_channel_count = 6,
10487 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010488 .unsol_event = alc_sku_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010489 .setup = alc888_acer_aspire_7730g_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010490 .init_hook = alc_hp_automute,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010491 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010492 [ALC883_MEDION] = {
10493 .mixers = { alc883_fivestack_mixer,
10494 alc883_chmode_mixer },
10495 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010496 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010497 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10498 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010499 .adc_nids = alc883_adc_nids_alt,
10500 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010501 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010502 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10503 .channel_mode = alc883_sixstack_modes,
10504 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010505 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010506 [ALC883_MEDION_WIM2160] = {
10507 .mixers = { alc883_medion_wim2160_mixer },
10508 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10509 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10510 .dac_nids = alc883_dac_nids,
10511 .dig_out_nid = ALC883_DIGOUT_NID,
10512 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10513 .adc_nids = alc883_adc_nids,
10514 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10515 .channel_mode = alc883_3ST_2ch_modes,
10516 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010517 .unsol_event = alc_sku_unsol_event,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010518 .setup = alc883_medion_wim2160_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010519 .init_hook = alc_hp_automute,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010520 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010521 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010522 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010523 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10524 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10525 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010526 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10527 .channel_mode = alc883_3ST_2ch_modes,
10528 .input_mux = &alc883_capture_source,
10529 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010530 [ALC883_CLEVO_M540R] = {
10531 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10532 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10533 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10534 .dac_nids = alc883_dac_nids,
10535 .dig_out_nid = ALC883_DIGOUT_NID,
10536 .dig_in_nid = ALC883_DIGIN_NID,
10537 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10538 .channel_mode = alc883_3ST_6ch_clevo_modes,
10539 .need_dac_fix = 1,
10540 .input_mux = &alc883_capture_source,
10541 /* This machine has the hardware HP auto-muting, thus
10542 * we need no software mute via unsol event
10543 */
10544 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010545 [ALC883_CLEVO_M720] = {
10546 .mixers = { alc883_clevo_m720_mixer },
10547 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010548 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10549 .dac_nids = alc883_dac_nids,
10550 .dig_out_nid = ALC883_DIGOUT_NID,
10551 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10552 .channel_mode = alc883_3ST_2ch_modes,
10553 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010554 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010555 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010556 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010557 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010558 [ALC883_LENOVO_101E_2ch] = {
10559 .mixers = { alc883_lenovo_101e_2ch_mixer},
10560 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10561 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10562 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010563 .adc_nids = alc883_adc_nids_alt,
10564 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010565 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010566 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10567 .channel_mode = alc883_3ST_2ch_modes,
10568 .input_mux = &alc883_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010569 .setup = alc883_lenovo_101e_setup,
10570 .unsol_event = alc_sku_unsol_event,
10571 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010572 },
Kailang Yang272a5272007-05-14 11:00:38 +020010573 [ALC883_LENOVO_NB0763] = {
10574 .mixers = { alc883_lenovo_nb0763_mixer },
10575 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10576 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10577 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010578 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10579 .channel_mode = alc883_3ST_2ch_modes,
10580 .need_dac_fix = 1,
10581 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010582 .unsol_event = alc_sku_unsol_event,
Takashi Iwaidc427172010-11-29 07:42:59 +010010583 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010584 .init_hook = alc_hp_automute,
Kailang Yang272a5272007-05-14 11:00:38 +020010585 },
10586 [ALC888_LENOVO_MS7195_DIG] = {
10587 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10588 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10589 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10590 .dac_nids = alc883_dac_nids,
10591 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010592 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10593 .channel_mode = alc883_3ST_6ch_modes,
10594 .need_dac_fix = 1,
10595 .input_mux = &alc883_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020010596 .unsol_event = alc_sku_unsol_event,
10597 .setup = alc888_lenovo_ms7195_setup,
10598 .init_hook = alc_inithook,
Kailang Yang189609a2007-08-20 11:31:23 +020010599 },
10600 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010601 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010602 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10603 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10604 .dac_nids = alc883_dac_nids,
10605 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010606 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10607 .channel_mode = alc883_3ST_2ch_modes,
10608 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010609 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010610 .setup = alc883_haier_w66_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010611 .init_hook = alc_hp_automute,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010612 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010613 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010614 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010615 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010616 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10617 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010618 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10619 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010620 .need_dac_fix = 1,
10621 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010622 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010623 .setup = alc888_3st_hp_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010624 .init_hook = alc_hp_automute,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010625 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010626 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010627 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010628 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10629 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10630 .dac_nids = alc883_dac_nids,
10631 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010632 .dig_in_nid = ALC883_DIGIN_NID,
10633 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10634 .channel_mode = alc883_sixstack_modes,
10635 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010636 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010637 .setup = alc888_6st_dell_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010638 .init_hook = alc_hp_automute,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010639 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010640 [ALC883_MITAC] = {
10641 .mixers = { alc883_mitac_mixer },
10642 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10643 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10644 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010645 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10646 .channel_mode = alc883_3ST_2ch_modes,
10647 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010648 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010649 .setup = alc883_mitac_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010650 .init_hook = alc_hp_automute,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010651 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010652 [ALC883_FUJITSU_PI2515] = {
10653 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10654 .init_verbs = { alc883_init_verbs,
10655 alc883_2ch_fujitsu_pi2515_verbs},
10656 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10657 .dac_nids = alc883_dac_nids,
10658 .dig_out_nid = ALC883_DIGOUT_NID,
10659 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10660 .channel_mode = alc883_3ST_2ch_modes,
10661 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010662 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010663 .setup = alc883_2ch_fujitsu_pi2515_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010664 .init_hook = alc_hp_automute,
Jiang zhefb97dc62008-03-06 11:07:11 +010010665 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010666 [ALC888_FUJITSU_XA3530] = {
10667 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10668 .init_verbs = { alc883_init_verbs,
10669 alc888_fujitsu_xa3530_verbs },
10670 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10671 .dac_nids = alc883_dac_nids,
10672 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10673 .adc_nids = alc883_adc_nids_rev,
10674 .capsrc_nids = alc883_capsrc_nids_rev,
10675 .dig_out_nid = ALC883_DIGOUT_NID,
10676 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10677 .channel_mode = alc888_4ST_8ch_intel_modes,
10678 .num_mux_defs =
10679 ARRAY_SIZE(alc888_2_capture_sources),
10680 .input_mux = alc888_2_capture_sources,
Takashi Iwaid922b512011-04-28 12:18:53 +020010681 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010682 .setup = alc888_fujitsu_xa3530_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010683 .init_hook = alc_hp_automute,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010684 },
Kailang Yange2757d52008-08-26 13:17:46 +020010685 [ALC888_LENOVO_SKY] = {
10686 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10687 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10688 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10689 .dac_nids = alc883_dac_nids,
10690 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010691 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10692 .channel_mode = alc883_sixstack_modes,
10693 .need_dac_fix = 1,
10694 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010695 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010696 .setup = alc888_lenovo_sky_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010697 .init_hook = alc_hp_automute,
Kailang Yange2757d52008-08-26 13:17:46 +020010698 },
10699 [ALC888_ASUS_M90V] = {
10700 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10701 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10702 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10703 .dac_nids = alc883_dac_nids,
10704 .dig_out_nid = ALC883_DIGOUT_NID,
10705 .dig_in_nid = ALC883_DIGIN_NID,
10706 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10707 .channel_mode = alc883_3ST_6ch_modes,
10708 .need_dac_fix = 1,
10709 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010710 .unsol_event = alc_sku_unsol_event,
10711 .setup = alc883_mode2_setup,
10712 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010713 },
10714 [ALC888_ASUS_EEE1601] = {
10715 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010716 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010717 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10718 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10719 .dac_nids = alc883_dac_nids,
10720 .dig_out_nid = ALC883_DIGOUT_NID,
10721 .dig_in_nid = ALC883_DIGIN_NID,
10722 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10723 .channel_mode = alc883_3ST_2ch_modes,
10724 .need_dac_fix = 1,
10725 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010726 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010727 .init_hook = alc883_eee1601_inithook,
10728 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010729 [ALC1200_ASUS_P5Q] = {
10730 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10731 .init_verbs = { alc883_init_verbs },
10732 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10733 .dac_nids = alc883_dac_nids,
10734 .dig_out_nid = ALC1200_DIGOUT_NID,
10735 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010736 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010737 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10738 .channel_mode = alc883_sixstack_modes,
10739 .input_mux = &alc883_capture_source,
10740 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010741 [ALC889A_MB31] = {
10742 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10743 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10744 alc880_gpio1_init_verbs },
10745 .adc_nids = alc883_adc_nids,
10746 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010747 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010748 .dac_nids = alc883_dac_nids,
10749 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10750 .channel_mode = alc889A_mb31_6ch_modes,
10751 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10752 .input_mux = &alc889A_mb31_capture_source,
10753 .dig_out_nid = ALC883_DIGOUT_NID,
10754 .unsol_event = alc889A_mb31_unsol_event,
10755 .init_hook = alc889A_mb31_automute,
10756 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010757 [ALC883_SONY_VAIO_TT] = {
10758 .mixers = { alc883_vaiott_mixer },
10759 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10760 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10761 .dac_nids = alc883_dac_nids,
10762 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10763 .channel_mode = alc883_3ST_2ch_modes,
10764 .input_mux = &alc883_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020010765 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010766 .setup = alc883_vaiott_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020010767 .init_hook = alc_hp_automute,
Guido Günther3e1647c2009-06-05 00:47:26 +020010768 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010769};
10770
10771
10772/*
Takashi Iwai49535502009-06-30 15:28:30 +020010773 * Pin config fixes
10774 */
10775enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010776 PINFIX_ABIT_AW9D_MAX,
David Henningsson32eea382011-03-04 13:37:50 +010010777 PINFIX_LENOVO_Y530,
Takashi Iwai954a29c2010-07-30 10:55:44 +020010778 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010779 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai49535502009-06-30 15:28:30 +020010780};
10781
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010782static const struct alc_fixup alc882_fixups[] = {
10783 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010784 .type = ALC_FIXUP_PINS,
10785 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010786 { 0x15, 0x01080104 }, /* side */
10787 { 0x16, 0x01011012 }, /* rear */
10788 { 0x17, 0x01016011 }, /* clfe */
10789 { }
10790 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010791 },
David Henningsson32eea382011-03-04 13:37:50 +010010792 [PINFIX_LENOVO_Y530] = {
10793 .type = ALC_FIXUP_PINS,
10794 .v.pins = (const struct alc_pincfg[]) {
10795 { 0x15, 0x99130112 }, /* rear int speakers */
10796 { 0x16, 0x99130111 }, /* subwoofer */
10797 { }
10798 }
10799 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010800 [PINFIX_PB_M5210] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010801 .type = ALC_FIXUP_VERBS,
10802 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020010803 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10804 {}
10805 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010806 },
David Henningssonc3d226a2010-10-14 15:42:08 +020010807 [PINFIX_ACER_ASPIRE_7736] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010010808 .type = ALC_FIXUP_SKU,
10809 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonc3d226a2010-10-14 15:42:08 +020010810 },
Takashi Iwai49535502009-06-30 15:28:30 +020010811};
10812
Takashi Iwaia9111322011-05-02 11:30:18 +020010813static const struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010814 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
David Henningsson32eea382011-03-04 13:37:50 +010010815 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", PINFIX_LENOVO_Y530),
Takashi Iwai49535502009-06-30 15:28:30 +020010816 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020010817 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai49535502009-06-30 15:28:30 +020010818 {}
10819};
10820
10821/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010822 * BIOS auto configuration
10823 */
Takashi Iwai21268962011-07-07 15:01:13 +020010824static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
10825{
10826 struct alc_spec *spec = codec->spec;
10827 hda_nid_t nid;
10828
10829 nid = spec->adc_nids[adc_idx];
10830 /* mute ADC */
10831 if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) {
10832 snd_hda_codec_write(codec, nid, 0,
10833 AC_VERB_SET_AMP_GAIN_MUTE,
10834 AMP_IN_MUTE(0));
10835 return;
10836 }
10837 if (!spec->capsrc_nids)
10838 return;
10839 nid = spec->capsrc_nids[adc_idx];
10840 if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE)
10841 snd_hda_codec_write(codec, nid, 0,
10842 AC_VERB_SET_AMP_GAIN_MUTE,
10843 AMP_OUT_MUTE);
10844}
10845
Takashi Iwaif970de22011-07-06 17:39:59 +020010846static void alc_auto_init_input_src(struct hda_codec *codec)
Takashi Iwai49535502009-06-30 15:28:30 +020010847{
10848 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +020010849 int c, nums;
Takashi Iwai49535502009-06-30 15:28:30 +020010850
Takashi Iwai21268962011-07-07 15:01:13 +020010851 for (c = 0; c < spec->num_adc_nids; c++)
10852 alc_auto_init_adc(codec, c);
10853 if (spec->dyn_adc_switch)
10854 nums = 1;
10855 else
10856 nums = spec->num_adc_nids;
10857 for (c = 0; c < nums; c++)
10858 alc_mux_select(codec, 0, spec->cur_mux[c], true);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010859}
10860
Takashi Iwai49535502009-06-30 15:28:30 +020010861/* add mic boosts if needed */
10862static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010863{
10864 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010865 struct auto_pin_cfg *cfg = &spec->autocfg;
David Henningsson5322bf22011-01-05 11:03:56 +010010866 int i, err;
Takashi Iwai53e8c322010-12-17 15:23:41 +010010867 int type_idx = 0;
Takashi Iwai49535502009-06-30 15:28:30 +020010868 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010010869 const char *prev_label = NULL;
Takashi Iwai49535502009-06-30 15:28:30 +020010870
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010871 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020010872 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010873 break;
10874 nid = cfg->inputs[i].pin;
10875 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
David Henningsson5322bf22011-01-05 11:03:56 +010010876 const char *label;
10877 char boost_label[32];
10878
10879 label = hda_get_autocfg_input_label(codec, cfg, i);
10880 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai53e8c322010-12-17 15:23:41 +010010881 type_idx++;
10882 else
10883 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +010010884 prev_label = label;
10885
10886 snprintf(boost_label, sizeof(boost_label),
10887 "%s Boost Volume", label);
10888 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10889 boost_label, type_idx,
Takashi Iwai49535502009-06-30 15:28:30 +020010890 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010891 if (err < 0)
10892 return err;
10893 }
Takashi Iwai49535502009-06-30 15:28:30 +020010894 }
10895 return 0;
10896}
10897
10898/* almost identical with ALC880 parser... */
10899static int alc882_parse_auto_config(struct hda_codec *codec)
10900{
10901 struct alc_spec *spec = codec->spec;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020010902 static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010903 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010904
Takashi Iwai05f5f472009-08-25 13:10:18 +020010905 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10906 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010907 if (err < 0)
10908 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010909 if (!spec->autocfg.line_outs)
10910 return 0; /* can't find valid BIOS pin config */
10911
Takashi Iwai343a04b2011-07-06 14:28:39 +020010912 err = alc_auto_fill_dac_nids(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010913 if (err < 0)
10914 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010915 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020010916 if (err < 0)
10917 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010918 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010919 if (err < 0)
10920 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010921 err = alc_auto_create_hp_out(codec);
Takashi Iwai489008c2010-04-07 09:06:00 +020010922 if (err < 0)
10923 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010924 err = alc_auto_create_speaker_out(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010925 if (err < 0)
10926 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020010927 err = alc_auto_create_input_ctls(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010928 if (err < 0)
10929 return err;
10930
10931 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10932
Takashi Iwai757899a2010-07-30 10:48:14 +020010933 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010934
10935 if (spec->kctls.list)
10936 add_mixer(spec, spec->kctls.list);
10937
Takashi Iwai776e1842007-08-29 15:07:11 +020010938 err = alc_auto_add_mic_boost(codec);
10939 if (err < 0)
10940 return err;
10941
Takashi Iwai21268962011-07-07 15:01:13 +020010942 alc_remove_invalid_adc_nids(codec);
10943
10944 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
10945 alc_auto_check_switches(codec);
10946
Takashi Iwai776e1842007-08-29 15:07:11 +020010947 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010948}
10949
10950/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010951static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010952{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010953 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020010954 alc_auto_init_multi_out(codec);
10955 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020010956 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020010957 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010958 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010959 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010960 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010961}
10962
Takashi Iwai49535502009-06-30 15:28:30 +020010963static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010964{
10965 struct alc_spec *spec;
10966 int err, board_config;
10967
10968 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10969 if (spec == NULL)
10970 return -ENOMEM;
10971
10972 codec->spec = spec;
10973
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020010974 spec->mixer_nid = 0x0b;
10975
Takashi Iwai49535502009-06-30 15:28:30 +020010976 switch (codec->vendor_id) {
10977 case 0x10ec0882:
10978 case 0x10ec0885:
10979 break;
10980 default:
10981 /* ALC883 and variants */
10982 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10983 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010984 }
10985
Takashi Iwai49535502009-06-30 15:28:30 +020010986 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10987 alc882_models,
10988 alc882_cfg_tbl);
10989
10990 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10991 board_config = snd_hda_check_board_codec_sid_config(codec,
10992 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10993
10994 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010995 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020010996 codec->chip_name);
10997 board_config = ALC882_AUTO;
10998 }
10999
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011000 if (board_config == ALC882_AUTO) {
11001 alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
11002 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
11003 }
Takashi Iwai49535502009-06-30 15:28:30 +020011004
David Henningsson90622912010-10-14 14:50:18 +020011005 alc_auto_parse_customize_define(codec);
11006
Takashi Iwai49535502009-06-30 15:28:30 +020011007 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011008 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020011009 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011010 if (err < 0) {
11011 alc_free(codec);
11012 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011013 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011014 printk(KERN_INFO
11015 "hda_codec: Cannot set up configuration "
11016 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020011017 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011018 }
11019 }
11020
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011021 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020011022 err = snd_hda_attach_beep_device(codec, 0x1);
11023 if (err < 0) {
11024 alc_free(codec);
11025 return err;
11026 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090011027 }
11028
Takashi Iwai49535502009-06-30 15:28:30 +020011029 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020011030 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011031
Takashi Iwai49535502009-06-30 15:28:30 +020011032 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020011033 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020011034 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020011035 alc_remove_invalid_adc_nids(codec);
Kailang Yang2f893282008-05-27 12:14:47 +020011036 }
11037
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011038 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011039
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011040 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011041 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011042
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010011043 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011044
Takashi Iwai2134ea42008-01-10 16:53:55 +010011045 spec->vmaster_nid = 0x0c;
11046
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011047 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020011048 if (board_config == ALC882_AUTO)
11049 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011050
11051 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011052#ifdef CONFIG_SND_HDA_POWER_SAVE
11053 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020011054 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011055#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011056
11057 return 0;
11058}
11059
Takashi Iwai49535502009-06-30 15:28:30 +020011060
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011061/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011062 * ALC262 support
11063 */
11064
11065#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11066#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11067
11068#define alc262_dac_nids alc260_dac_nids
11069#define alc262_adc_nids alc882_adc_nids
11070#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011071#define alc262_capsrc_nids alc882_capsrc_nids
11072#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011073
11074#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011075#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011076
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011077static const hda_nid_t alc262_dmic_adc_nids[1] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011078 /* ADC0 */
11079 0x09
11080};
11081
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020011082static const hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
Kailang Yang4e555fe2008-08-26 13:05:55 +020011083
Takashi Iwaia9111322011-05-02 11:30:18 +020011084static const struct snd_kcontrol_new alc262_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011085 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11086 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11087 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11088 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11089 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11090 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11091 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11092 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011093 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011094 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11095 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011096 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011097 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11098 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11099 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11100 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011101 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011102};
11103
Takashi Iwaice875f02008-01-28 18:17:43 +010011104/* update HP, line and mono-out pins according to the master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011105#define alc262_hp_master_update alc260_hp_master_update
Takashi Iwaice875f02008-01-28 18:17:43 +010011106
Takashi Iwaie9427962011-04-28 15:46:07 +020011107static void alc262_hp_bpc_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011108{
11109 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011110
Takashi Iwaie9427962011-04-28 15:46:07 +020011111 spec->autocfg.hp_pins[0] = 0x1b;
11112 spec->autocfg.speaker_pins[0] = 0x16;
11113 spec->automute = 1;
11114 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011115}
11116
Takashi Iwaie9427962011-04-28 15:46:07 +020011117static void alc262_hp_wildwest_setup(struct hda_codec *codec)
Takashi Iwaice875f02008-01-28 18:17:43 +010011118{
11119 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011120
Takashi Iwaie9427962011-04-28 15:46:07 +020011121 spec->autocfg.hp_pins[0] = 0x15;
11122 spec->autocfg.speaker_pins[0] = 0x16;
11123 spec->automute = 1;
11124 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwaice875f02008-01-28 18:17:43 +010011125}
11126
Takashi Iwaib72519b2009-05-08 14:31:55 +020011127#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011128#define alc262_hp_master_sw_put alc260_hp_master_sw_put
Takashi Iwaice875f02008-01-28 18:17:43 +010011129
Takashi Iwaib72519b2009-05-08 14:31:55 +020011130#define ALC262_HP_MASTER_SWITCH \
11131 { \
11132 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11133 .name = "Master Playback Switch", \
11134 .info = snd_ctl_boolean_mono_info, \
11135 .get = alc262_hp_master_sw_get, \
11136 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011137 }, \
11138 { \
11139 .iface = NID_MAPPING, \
11140 .name = "Master Playback Switch", \
11141 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011142 }
11143
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011144
Takashi Iwaia9111322011-05-02 11:30:18 +020011145static const struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011146 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011147 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11148 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11149 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011150 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11151 HDA_OUTPUT),
11152 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11153 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011154 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11155 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011156 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011157 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11158 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011159 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011160 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11161 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11162 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11163 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011164 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11165 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11166 { } /* end */
11167};
11168
Takashi Iwaia9111322011-05-02 11:30:18 +020011169static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011170 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011171 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11172 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11173 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11174 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011175 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11176 HDA_OUTPUT),
11177 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11178 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011179 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11180 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011181 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011182 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11183 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11184 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11185 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011186 { } /* end */
11187};
11188
Takashi Iwaia9111322011-05-02 11:30:18 +020011189static const struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010011190 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11191 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011192 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011193 { } /* end */
11194};
11195
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011196/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011197static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011198{
11199 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011200
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011201 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011202 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020011203 spec->automute = 1;
11204 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011205}
11206
Takashi Iwaia9111322011-05-02 11:30:18 +020011207static const struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011208 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11209 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011210 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11211 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11212 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11213 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011214 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011215 { } /* end */
11216};
11217
Takashi Iwaia9111322011-05-02 11:30:18 +020011218static const struct hda_verb alc262_hp_t5735_verbs[] = {
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011219 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11220 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11221
11222 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11223 { }
11224};
11225
Takashi Iwaia9111322011-05-02 11:30:18 +020011226static const struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011227 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11228 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011229 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11230 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011231 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11232 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11233 { } /* end */
11234};
11235
Takashi Iwaia9111322011-05-02 11:30:18 +020011236static const struct hda_verb alc262_hp_rp5700_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010011237 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11238 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11239 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11240 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11241 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11242 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11243 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11244 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11245 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11246 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11247 {}
11248};
11249
Takashi Iwaia9111322011-05-02 11:30:18 +020011250static const struct hda_input_mux alc262_hp_rp5700_capture_source = {
Kailang Yang8c427222008-01-10 13:03:59 +010011251 .num_items = 1,
11252 .items = {
11253 { "Line", 0x1 },
11254 },
11255};
11256
Takashi Iwai42171c12009-05-08 14:11:43 +020011257/* bind hp and internal speaker mute (with plug check) as master switch */
Takashi Iwaie9427962011-04-28 15:46:07 +020011258#define alc262_hippo_master_update alc262_hp_master_update
Takashi Iwai42171c12009-05-08 14:11:43 +020011259#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
Takashi Iwaie9427962011-04-28 15:46:07 +020011260#define alc262_hippo_master_sw_put alc262_hp_master_sw_put
Takashi Iwai5b319542007-07-26 11:49:22 +020011261
Takashi Iwai42171c12009-05-08 14:11:43 +020011262#define ALC262_HIPPO_MASTER_SWITCH \
11263 { \
11264 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11265 .name = "Master Playback Switch", \
11266 .info = snd_ctl_boolean_mono_info, \
11267 .get = alc262_hippo_master_sw_get, \
11268 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011269 }, \
11270 { \
11271 .iface = NID_MAPPING, \
11272 .name = "Master Playback Switch", \
11273 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11274 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011275 }
11276
Takashi Iwaia9111322011-05-02 11:30:18 +020011277static const struct snd_kcontrol_new alc262_hippo_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011278 ALC262_HIPPO_MASTER_SWITCH,
11279 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11280 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11281 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11282 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11283 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11284 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11285 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011286 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011287 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11288 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011289 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011290 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11291 { } /* end */
11292};
11293
Takashi Iwaia9111322011-05-02 11:30:18 +020011294static const struct snd_kcontrol_new alc262_hippo1_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011295 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11296 ALC262_HIPPO_MASTER_SWITCH,
11297 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11298 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11299 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11300 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11301 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11302 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011303 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011304 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11305 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011306 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011307 { } /* end */
11308};
11309
11310/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011311static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011312{
11313 struct alc_spec *spec = codec->spec;
11314
11315 spec->autocfg.hp_pins[0] = 0x15;
11316 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011317 spec->automute = 1;
11318 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011319}
11320
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011321static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011322{
11323 struct alc_spec *spec = codec->spec;
11324
11325 spec->autocfg.hp_pins[0] = 0x1b;
11326 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaie9427962011-04-28 15:46:07 +020011327 spec->automute = 1;
11328 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai42171c12009-05-08 14:11:43 +020011329}
11330
11331
Takashi Iwaia9111322011-05-02 11:30:18 +020011332static const struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011333 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011334 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011335 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11336 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11337 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11338 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11339 { } /* end */
11340};
11341
Takashi Iwaia9111322011-05-02 11:30:18 +020011342static const struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011343 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11344 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011345 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11346 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11347 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11348 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11349 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11350 { } /* end */
11351};
Kailang Yang272a5272007-05-14 11:00:38 +020011352
Takashi Iwaia9111322011-05-02 11:30:18 +020011353static const struct snd_kcontrol_new alc262_tyan_mixer[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011354 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11355 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11356 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11357 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11358 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11359 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11360 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11361 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011362 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011363 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11364 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011365 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011366 { } /* end */
11367};
11368
Takashi Iwaia9111322011-05-02 11:30:18 +020011369static const struct hda_verb alc262_tyan_verbs[] = {
Tony Vroonba340e82009-02-02 19:01:30 +000011370 /* Headphone automute */
11371 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11372 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11373 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11374
11375 /* P11 AUX_IN, white 4-pin connector */
11376 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11377 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11378 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11379 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11380
11381 {}
11382};
11383
11384/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011385static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011386{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011387 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011388
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011389 spec->autocfg.hp_pins[0] = 0x1b;
11390 spec->autocfg.speaker_pins[0] = 0x15;
Takashi Iwaid922b512011-04-28 12:18:53 +020011391 spec->automute = 1;
11392 spec->automute_mode = ALC_AUTOMUTE_AMP;
Tony Vroonba340e82009-02-02 19:01:30 +000011393}
11394
Tony Vroonba340e82009-02-02 19:01:30 +000011395
Kailang Yangdf694da2005-12-05 19:42:22 +010011396#define alc262_capture_mixer alc882_capture_mixer
11397#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11398
11399/*
11400 * generic initialization of ADC, input mixers and output mixers
11401 */
Takashi Iwaia9111322011-05-02 11:30:18 +020011402static const struct hda_verb alc262_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010011403 /*
11404 * Unmute ADC0-2 and set the default input to mic-in
11405 */
11406 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11407 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11408 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11409 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11410 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11411 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11412
Takashi Iwaicb53c622007-08-10 17:21:45 +020011413 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011414 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011415 * Note: PASD motherboards uses the Line In 2 as the input for
11416 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011417 */
11418 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011419 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11420 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11421 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11422 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11423 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011424
11425 /*
11426 * Set up output mixers (0x0c - 0x0e)
11427 */
11428 /* set vol=0 to output mixers */
11429 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11430 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11431 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11432 /* set up input amps for analog loopback */
11433 /* Amp Indices: DAC = 0, mixer = 1 */
11434 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11435 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11436 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11437 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11438 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11439 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11440
11441 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11442 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11443 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11444 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11445 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11446 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11447
11448 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11449 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11450 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11451 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11452 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011453
Kailang Yangdf694da2005-12-05 19:42:22 +010011454 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11455 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011456
Kailang Yangdf694da2005-12-05 19:42:22 +010011457 /* FIXME: use matrix-type input source selection */
11458 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11459 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11460 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11461 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11462 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11463 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11464 /* Input mixer2 */
11465 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11466 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11467 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11468 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11469 /* Input mixer3 */
11470 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11471 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11472 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011473 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011474
11475 { }
11476};
11477
Takashi Iwaia9111322011-05-02 11:30:18 +020011478static const struct hda_verb alc262_eapd_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011479 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11480 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11481 { }
11482};
11483
Takashi Iwaia9111322011-05-02 11:30:18 +020011484static const struct hda_verb alc262_hippo1_unsol_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +020011485 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11486 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11487 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11488
11489 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11490 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11491 {}
11492};
11493
Takashi Iwaia9111322011-05-02 11:30:18 +020011494static const struct hda_verb alc262_sony_unsol_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020011495 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11496 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11497 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11498
11499 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11500 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011501 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011502};
11503
Takashi Iwaia9111322011-05-02 11:30:18 +020011504static const struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011505 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11506 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11508 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11509 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011510 { } /* end */
11511};
11512
Takashi Iwaia9111322011-05-02 11:30:18 +020011513static const struct hda_verb alc262_toshiba_s06_verbs[] = {
Kailang Yang4e555fe2008-08-26 13:05:55 +020011514 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11515 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11516 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11517 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11518 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11519 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11520 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11521 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11522 {}
11523};
11524
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011525static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011526{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011527 struct alc_spec *spec = codec->spec;
11528
11529 spec->autocfg.hp_pins[0] = 0x15;
11530 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai21268962011-07-07 15:01:13 +020011531 spec->ext_mic_pin = 0x18;
11532 spec->int_mic_pin = 0x12;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011533 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020011534 spec->automute = 1;
11535 spec->automute_mode = ALC_AUTOMUTE_PIN;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011536}
11537
Takashi Iwai834be882006-03-01 14:16:17 +010011538/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011539 * nec model
11540 * 0x15 = headphone
11541 * 0x16 = internal speaker
11542 * 0x18 = external mic
11543 */
11544
Takashi Iwaia9111322011-05-02 11:30:18 +020011545static const struct snd_kcontrol_new alc262_nec_mixer[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011546 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11547 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11548
11549 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11550 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011551 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011552
11553 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11554 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11555 { } /* end */
11556};
11557
Takashi Iwaia9111322011-05-02 11:30:18 +020011558static const struct hda_verb alc262_nec_verbs[] = {
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011559 /* Unmute Speaker */
11560 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11561
11562 /* Headphone */
11563 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11564 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11565
11566 /* External mic to headphone */
11567 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11568 /* External mic to speaker */
11569 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11570 {}
11571};
11572
11573/*
Takashi Iwai834be882006-03-01 14:16:17 +010011574 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011575 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11576 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011577 */
11578
Takashi Iwai20f5e0b2011-06-10 09:31:54 +020011579#define ALC_HP_EVENT ALC880_HP_EVENT
Takashi Iwai834be882006-03-01 14:16:17 +010011580
Takashi Iwaia9111322011-05-02 11:30:18 +020011581static const struct hda_verb alc262_fujitsu_unsol_verbs[] = {
Takashi Iwai834be882006-03-01 14:16:17 +010011582 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11583 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011584 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11585 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011586 {}
11587};
11588
Takashi Iwaia9111322011-05-02 11:30:18 +020011589static const struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011590 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11591 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11592 {}
11593};
11594
Takashi Iwaia9111322011-05-02 11:30:18 +020011595static const struct hda_verb alc262_lenovo_3000_init_verbs[] = {
Daniel T Chene2595322009-12-19 18:19:02 -050011596 /* Front Mic pin: input vref at 50% */
11597 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11598 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11599 {}
11600};
11601
Takashi Iwaia9111322011-05-02 11:30:18 +020011602static const struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011603 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011604 .items = {
11605 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011606 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011607 { "CD", 0x4 },
11608 },
11609};
11610
Takashi Iwaia9111322011-05-02 11:30:18 +020011611static const struct hda_input_mux alc262_HP_capture_source = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011612 .num_items = 5,
11613 .items = {
11614 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011615 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011616 { "Line", 0x2 },
11617 { "CD", 0x4 },
11618 { "AUX IN", 0x6 },
11619 },
11620};
11621
Takashi Iwaia9111322011-05-02 11:30:18 +020011622static const struct hda_input_mux alc262_HP_D7000_capture_source = {
zhejiangaccbe492007-08-31 12:36:05 +020011623 .num_items = 4,
11624 .items = {
11625 { "Mic", 0x0 },
11626 { "Front Mic", 0x2 },
11627 { "Line", 0x1 },
11628 { "CD", 0x4 },
11629 },
11630};
11631
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011632static void alc262_fujitsu_setup(struct hda_codec *codec)
Takashi Iwai834be882006-03-01 14:16:17 +010011633{
11634 struct alc_spec *spec = codec->spec;
Takashi Iwai834be882006-03-01 14:16:17 +010011635
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011636 spec->autocfg.hp_pins[0] = 0x14;
11637 spec->autocfg.hp_pins[1] = 0x1b;
11638 spec->autocfg.speaker_pins[0] = 0x15;
11639 spec->automute = 1;
11640 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011641}
11642
Takashi Iwai834be882006-03-01 14:16:17 +010011643/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaia9111322011-05-02 11:30:18 +020011644static const struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011645 .ops = &snd_hda_bind_vol,
11646 .values = {
11647 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11648 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11649 0
11650 },
11651};
Takashi Iwai834be882006-03-01 14:16:17 +010011652
Takashi Iwaia9111322011-05-02 11:30:18 +020011653static const struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011654 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011655 {
11656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11657 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011658 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
11659 .info = snd_ctl_boolean_mono_info,
11660 .get = alc262_hp_master_sw_get,
11661 .put = alc262_hp_master_sw_put,
Takashi Iwai834be882006-03-01 14:16:17 +010011662 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011663 {
11664 .iface = NID_MAPPING,
11665 .name = "Master Playback Switch",
11666 .private_value = 0x1b,
11667 },
Takashi Iwai834be882006-03-01 14:16:17 +010011668 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11669 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011670 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011671 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11672 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011673 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011674 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11675 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011676 { } /* end */
11677};
11678
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011679static void alc262_lenovo_3000_setup(struct hda_codec *codec)
Jiang zhe0e31daf2008-03-20 12:12:39 +010011680{
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011681 struct alc_spec *spec = codec->spec;
Jiang zhe0e31daf2008-03-20 12:12:39 +010011682
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011683 spec->autocfg.hp_pins[0] = 0x1b;
11684 spec->autocfg.speaker_pins[0] = 0x14;
11685 spec->autocfg.speaker_pins[1] = 0x16;
11686 spec->automute = 1;
11687 spec->automute_mode = ALC_AUTOMUTE_AMP;
Jiang zhe0e31daf2008-03-20 12:12:39 +010011688}
11689
Takashi Iwaia9111322011-05-02 11:30:18 +020011690static const struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
Jiang zhe0e31daf2008-03-20 12:12:39 +010011691 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11692 {
11693 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11694 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020011695 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
11696 .info = snd_ctl_boolean_mono_info,
11697 .get = alc262_hp_master_sw_get,
11698 .put = alc262_hp_master_sw_put,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011699 },
11700 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11701 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011702 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011703 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11704 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011705 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011706 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11707 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011708 { } /* end */
11709};
11710
Takashi Iwaia9111322011-05-02 11:30:18 +020011711static const struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011712 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011713 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011714 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11715 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011716 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011717 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11718 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011719 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011720 { } /* end */
11721};
11722
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011723/* additional init verbs for Benq laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020011724static const struct hda_verb alc262_EAPD_verbs[] = {
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011725 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11726 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11727 {}
11728};
11729
Takashi Iwaia9111322011-05-02 11:30:18 +020011730static const struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
Kailang Yang83c34212007-07-05 11:43:05 +020011731 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11732 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11733
11734 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11735 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11736 {}
11737};
11738
Tobin Davisf651b502007-10-26 12:40:47 +020011739/* Samsung Q1 Ultra Vista model setup */
Takashi Iwaia9111322011-05-02 11:30:18 +020011740static const struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011741 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11742 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011743 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11744 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011745 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
11746 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011747 { } /* end */
11748};
11749
Takashi Iwaia9111322011-05-02 11:30:18 +020011750static const struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011751 /* output mixer */
11752 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11753 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11754 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11755 /* speaker */
11756 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11757 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11758 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11759 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11760 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011761 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011762 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11763 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11764 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11765 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11766 /* internal mic */
11767 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11768 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11769 /* ADC, choose mic */
11770 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11771 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11772 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11773 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11774 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11775 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11776 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11777 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11778 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11779 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011780 {}
11781};
11782
Tobin Davisf651b502007-10-26 12:40:47 +020011783/* mute/unmute internal speaker according to the hp jack and mute state */
11784static void alc262_ultra_automute(struct hda_codec *codec)
11785{
11786 struct alc_spec *spec = codec->spec;
11787 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011788
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011789 mute = 0;
11790 /* auto-mute only when HP is used as HP */
11791 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011792 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011793 if (spec->jack_present)
11794 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011795 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011796 /* mute/unmute internal speaker */
11797 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11798 HDA_AMP_MUTE, mute);
11799 /* mute/unmute HP */
11800 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11801 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011802}
11803
11804/* unsolicited event for HP jack sensing */
11805static void alc262_ultra_unsol_event(struct hda_codec *codec,
11806 unsigned int res)
11807{
11808 if ((res >> 26) != ALC880_HP_EVENT)
11809 return;
11810 alc262_ultra_automute(codec);
11811}
11812
Takashi Iwaia9111322011-05-02 11:30:18 +020011813static const struct hda_input_mux alc262_ultra_capture_source = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011814 .num_items = 2,
11815 .items = {
11816 { "Mic", 0x1 },
11817 { "Headphone", 0x7 },
11818 },
11819};
11820
11821static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11822 struct snd_ctl_elem_value *ucontrol)
11823{
11824 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11825 struct alc_spec *spec = codec->spec;
11826 int ret;
11827
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011828 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011829 if (!ret)
11830 return 0;
11831 /* reprogram the HP pin as mic or HP according to the input source */
11832 snd_hda_codec_write_cache(codec, 0x15, 0,
11833 AC_VERB_SET_PIN_WIDGET_CONTROL,
11834 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
11835 alc262_ultra_automute(codec); /* mute/unmute HP */
11836 return ret;
11837}
11838
Takashi Iwaia9111322011-05-02 11:30:18 +020011839static const struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011840 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
11841 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
11842 {
11843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11844 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010011845 .info = alc_mux_enum_info,
11846 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011847 .put = alc262_ultra_mux_enum_put,
11848 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011849 {
11850 .iface = NID_MAPPING,
11851 .name = "Capture Source",
11852 .private_value = 0x15,
11853 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011854 { } /* end */
11855};
11856
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011857/* We use two mixers depending on the output pin; 0x16 is a mono output
11858 * and thus it's bound with a different mixer.
11859 * This function returns which mixer amp should be used.
11860 */
11861static int alc262_check_volbit(hda_nid_t nid)
11862{
11863 if (!nid)
11864 return 0;
11865 else if (nid == 0x16)
11866 return 2;
11867 else
11868 return 1;
11869}
11870
11871static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011872 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011873{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011874 unsigned long val;
11875 int vbit;
11876
11877 vbit = alc262_check_volbit(nid);
11878 if (!vbit)
11879 return 0;
11880 if (*vbits & vbit) /* a volume control for this mixer already there */
11881 return 0;
11882 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011883 if (vbit == 2)
11884 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
11885 else
11886 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011887 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011888}
11889
11890static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020011891 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011892{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011893 unsigned long val;
11894
11895 if (!nid)
11896 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011897 if (nid == 0x16)
11898 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
11899 else
11900 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020011901 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011902}
11903
Kailang Yangdf694da2005-12-05 19:42:22 +010011904/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011905static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
11906 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010011907{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011908 const char *pfx;
11909 int vbits;
Takashi Iwai6843ca12011-06-24 11:03:58 +020011910 int i, index, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010011911
11912 spec->multiout.num_dacs = 1; /* only use one dac */
11913 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaidda14412011-05-02 11:29:30 +020011914 spec->private_dac_nids[0] = 2;
Kailang Yangdf694da2005-12-05 19:42:22 +010011915
Takashi Iwai033688a2010-09-08 15:47:09 +020011916 for (i = 0; i < 2; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020011917 pfx = alc_get_line_out_pfx(spec, i, true, &index);
11918 if (!pfx)
11919 pfx = "PCM";
11920 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx,
11921 index);
Takashi Iwai033688a2010-09-08 15:47:09 +020011922 if (err < 0)
11923 return err;
11924 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
11925 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
11926 "Speaker", i);
11927 if (err < 0)
11928 return err;
11929 }
11930 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
11931 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
11932 "Headphone", i);
11933 if (err < 0)
11934 return err;
11935 }
11936 }
Kailang Yangdf694da2005-12-05 19:42:22 +010011937
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011938 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
11939 alc262_check_volbit(cfg->speaker_pins[0]) |
11940 alc262_check_volbit(cfg->hp_pins[0]);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020011941 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020011942 for (i = 0; i < 2; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020011943 pfx = alc_get_line_out_pfx(spec, i, true, &index);
11944 if (!pfx)
11945 pfx = "PCM";
Takashi Iwai033688a2010-09-08 15:47:09 +020011946 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
11947 &vbits, i);
11948 if (err < 0)
11949 return err;
11950 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
11951 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
11952 "Speaker", &vbits, i);
11953 if (err < 0)
11954 return err;
11955 }
11956 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
11957 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
11958 "Headphone", &vbits, i);
11959 if (err < 0)
11960 return err;
11961 }
11962 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011963 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010011964}
11965
Takashi Iwaia9111322011-05-02 11:30:18 +020011966static const struct hda_verb alc262_HP_BPC_init_verbs[] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011967 /*
11968 * Unmute ADC0-2 and set the default input to mic-in
11969 */
11970 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11971 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11972 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11973 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11974 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11975 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11976
Takashi Iwaicb53c622007-08-10 17:21:45 +020011977 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011978 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011979 * Note: PASD motherboards uses the Line In 2 as the input for
11980 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011981 */
11982 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011983 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11984 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11985 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11986 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11987 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11988 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11989 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020011990
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011991 /*
11992 * Set up output mixers (0x0c - 0x0e)
11993 */
11994 /* set vol=0 to output mixers */
11995 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11996 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11997 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11998
11999 /* set up input amps for analog loopback */
12000 /* Amp Indices: DAC = 0, mixer = 1 */
12001 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12002 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12003 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12004 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12005 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12006 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12007
Takashi Iwaice875f02008-01-28 18:17:43 +010012008 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012009 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12010 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12011
12012 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12013 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12014
12015 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12016 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12017
12018 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12019 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12020 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12021 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12022 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12023
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012024 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012025 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12026 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012027 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012028 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12029 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12030
12031
12032 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012033 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12034 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012035 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012036 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12037 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12038 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12039 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12040 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12041 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12042 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12043 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012044 /* Input mixer2 */
12045 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012046 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12047 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12048 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12049 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12050 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12051 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12052 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12053 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012054 /* Input mixer3 */
12055 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012056 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12057 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12058 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12059 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12060 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12061 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12062 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12063 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012064
Takashi Iwaice875f02008-01-28 18:17:43 +010012065 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12066
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012067 { }
12068};
12069
Takashi Iwaia9111322011-05-02 11:30:18 +020012070static const struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
Kailang Yangcd7509a2007-01-26 18:33:17 +010012071 /*
12072 * Unmute ADC0-2 and set the default input to mic-in
12073 */
12074 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12075 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12076 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12077 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12078 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12079 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12080
Takashi Iwaicb53c622007-08-10 17:21:45 +020012081 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012082 * mixer widget
12083 * Note: PASD motherboards uses the Line In 2 as the input for front
12084 * panel mic (mic 2)
12085 */
12086 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012087 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12088 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12089 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12090 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12091 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12092 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12093 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12094 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012095 /*
12096 * Set up output mixers (0x0c - 0x0e)
12097 */
12098 /* set vol=0 to output mixers */
12099 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12100 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12101 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12102
12103 /* set up input amps for analog loopback */
12104 /* Amp Indices: DAC = 0, mixer = 1 */
12105 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12106 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12107 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12108 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12109 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12110 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12111
12112
12113 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12114 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12115 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12116 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12117 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12118 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12119 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12120
12121 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12122 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12123
12124 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12125 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12126
12127 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12128 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12129 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12130 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12131 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12132 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12133
12134 /* FIXME: use matrix-type input source selection */
12135 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12136 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12137 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12138 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12139 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12140 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12141 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12142 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12143 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12144 /* Input mixer2 */
12145 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12146 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12147 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12148 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12149 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12150 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12151 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12152 /* Input mixer3 */
12153 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12154 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12155 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12156 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12157 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12158 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12159 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12160
Takashi Iwaice875f02008-01-28 18:17:43 +010012161 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12162
Kailang Yangcd7509a2007-01-26 18:33:17 +010012163 { }
12164};
12165
Takashi Iwaia9111322011-05-02 11:30:18 +020012166static const struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012167
12168 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12169 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12170 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12171
12172 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12173 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12174 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12175 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12176
12177 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12178 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12179 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12180 {}
12181};
12182
Takashi Iwai18675e42010-09-08 15:55:44 +020012183/*
12184 * Pin config fixes
12185 */
12186enum {
12187 PINFIX_FSC_H270,
David Henningssond2a19da2011-06-22 09:58:37 +020012188 PINFIX_HP_Z200,
Takashi Iwai18675e42010-09-08 15:55:44 +020012189};
12190
12191static const struct alc_fixup alc262_fixups[] = {
12192 [PINFIX_FSC_H270] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012193 .type = ALC_FIXUP_PINS,
12194 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai18675e42010-09-08 15:55:44 +020012195 { 0x14, 0x99130110 }, /* speaker */
12196 { 0x15, 0x0221142f }, /* front HP */
12197 { 0x1b, 0x0121141f }, /* rear HP */
12198 { }
12199 }
12200 },
David Henningssond2a19da2011-06-22 09:58:37 +020012201 [PINFIX_HP_Z200] = {
12202 .type = ALC_FIXUP_PINS,
12203 .v.pins = (const struct alc_pincfg[]) {
12204 { 0x16, 0x99130120 }, /* internal speaker */
12205 { }
12206 }
12207 },
Takashi Iwai18675e42010-09-08 15:55:44 +020012208};
12209
Takashi Iwaia9111322011-05-02 11:30:18 +020012210static const struct snd_pci_quirk alc262_fixup_tbl[] = {
David Henningssond2a19da2011-06-22 09:58:37 +020012211 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", PINFIX_HP_Z200),
Takashi Iwai18675e42010-09-08 15:55:44 +020012212 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12213 {}
12214};
12215
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012216
Takashi Iwaicb53c622007-08-10 17:21:45 +020012217#ifdef CONFIG_SND_HDA_POWER_SAVE
12218#define alc262_loopbacks alc880_loopbacks
12219#endif
12220
Kailang Yangdf694da2005-12-05 19:42:22 +010012221/*
12222 * BIOS auto configuration
12223 */
12224static int alc262_parse_auto_config(struct hda_codec *codec)
12225{
12226 struct alc_spec *spec = codec->spec;
12227 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012228 static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010012229
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012230 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12231 alc262_ignore);
12232 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012233 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012234 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012235 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012236 spec->multiout.max_channels = 2;
12237 spec->no_analog = 1;
12238 goto dig_only;
12239 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012240 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012241 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012242 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12243 if (err < 0)
12244 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020012245 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012246 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012247 return err;
12248
12249 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12250
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012251 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012252 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012253
Takashi Iwai603c4012008-07-30 15:01:44 +020012254 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012255 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012256
Takashi Iwai776e1842007-08-29 15:07:11 +020012257 err = alc_auto_add_mic_boost(codec);
12258 if (err < 0)
12259 return err;
12260
Takashi Iwai21268962011-07-07 15:01:13 +020012261 alc_remove_invalid_adc_nids(codec);
12262
Kailang Yang6227cdc2010-02-25 08:36:52 +010012263 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai21268962011-07-07 15:01:13 +020012264 alc_auto_check_switches(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012265
Kailang Yangdf694da2005-12-05 19:42:22 +010012266 return 1;
12267}
12268
Kailang Yangdf694da2005-12-05 19:42:22 +010012269
12270/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012271static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012272{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012273 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020012274 alc_auto_init_multi_out(codec);
12275 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020012276 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020012277 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012278 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012279 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012280 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012281}
12282
12283/*
12284 * configuration and preset
12285 */
Takashi Iwaiea734962011-01-17 11:29:34 +010012286static const char * const alc262_models[ALC262_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012287 [ALC262_BASIC] = "basic",
12288 [ALC262_HIPPO] = "hippo",
12289 [ALC262_HIPPO_1] = "hippo_1",
12290 [ALC262_FUJITSU] = "fujitsu",
12291 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012292 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012293 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012294 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012295 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012296 [ALC262_BENQ_T31] = "benq-t31",
12297 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012298 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012299 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012300 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012301 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012302 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012303 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012304 [ALC262_AUTO] = "auto",
12305};
12306
Takashi Iwaia9111322011-05-02 11:30:18 +020012307static const struct snd_pci_quirk alc262_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012308 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012309 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012310 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12311 ALC262_HP_BPC),
12312 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12313 ALC262_HP_BPC),
Takashi Iwai5734a072011-01-19 17:07:12 +010012314 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1500, "HP z series",
12315 ALC262_HP_BPC),
David Henningssond2a19da2011-06-22 09:58:37 +020012316 SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200",
12317 ALC262_AUTO),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012318 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12319 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012320 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012321 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012322 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012323 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012324 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012325 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012326 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012327 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012328 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12329 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12330 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012331 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12332 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012333 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012334 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012335 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012336 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012337 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012338 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012339 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012340 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012341#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012342 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12343 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012344#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012345 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012346 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012347 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012348 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012349 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012350 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012351 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12352 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012353 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012354 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012355 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012356 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012357 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012358 {}
12359};
12360
Takashi Iwaia9111322011-05-02 11:30:18 +020012361static const struct alc_config_preset alc262_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010012362 [ALC262_BASIC] = {
12363 .mixers = { alc262_base_mixer },
12364 .init_verbs = { alc262_init_verbs },
12365 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12366 .dac_nids = alc262_dac_nids,
12367 .hp_nid = 0x03,
12368 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12369 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012370 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012371 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012372 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012373 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012374 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012375 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12376 .dac_nids = alc262_dac_nids,
12377 .hp_nid = 0x03,
12378 .dig_out_nid = ALC262_DIGOUT_NID,
12379 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12380 .channel_mode = alc262_modes,
12381 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012382 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012383 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012384 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012385 },
12386 [ALC262_HIPPO_1] = {
12387 .mixers = { alc262_hippo1_mixer },
12388 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12389 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12390 .dac_nids = alc262_dac_nids,
12391 .hp_nid = 0x02,
12392 .dig_out_nid = ALC262_DIGOUT_NID,
12393 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12394 .channel_mode = alc262_modes,
12395 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012396 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012397 .setup = alc262_hippo1_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012398 .init_hook = alc_inithook,
Kailang Yangccc656c2006-10-17 12:32:26 +020012399 },
Takashi Iwai834be882006-03-01 14:16:17 +010012400 [ALC262_FUJITSU] = {
12401 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012402 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12403 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012404 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12405 .dac_nids = alc262_dac_nids,
12406 .hp_nid = 0x03,
12407 .dig_out_nid = ALC262_DIGOUT_NID,
12408 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12409 .channel_mode = alc262_modes,
12410 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012411 .unsol_event = alc_sku_unsol_event,
12412 .setup = alc262_fujitsu_setup,
12413 .init_hook = alc_inithook,
Takashi Iwai834be882006-03-01 14:16:17 +010012414 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012415 [ALC262_HP_BPC] = {
12416 .mixers = { alc262_HP_BPC_mixer },
12417 .init_verbs = { alc262_HP_BPC_init_verbs },
12418 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12419 .dac_nids = alc262_dac_nids,
12420 .hp_nid = 0x03,
12421 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12422 .channel_mode = alc262_modes,
12423 .input_mux = &alc262_HP_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012424 .unsol_event = alc_sku_unsol_event,
12425 .setup = alc262_hp_bpc_setup,
12426 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012427 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012428 [ALC262_HP_BPC_D7000_WF] = {
12429 .mixers = { alc262_HP_BPC_WildWest_mixer },
12430 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12431 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12432 .dac_nids = alc262_dac_nids,
12433 .hp_nid = 0x03,
12434 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12435 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012436 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012437 .unsol_event = alc_sku_unsol_event,
12438 .setup = alc262_hp_wildwest_setup,
12439 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012440 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012441 [ALC262_HP_BPC_D7000_WL] = {
12442 .mixers = { alc262_HP_BPC_WildWest_mixer,
12443 alc262_HP_BPC_WildWest_option_mixer },
12444 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12445 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12446 .dac_nids = alc262_dac_nids,
12447 .hp_nid = 0x03,
12448 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12449 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012450 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012451 .unsol_event = alc_sku_unsol_event,
12452 .setup = alc262_hp_wildwest_setup,
12453 .init_hook = alc_inithook,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012454 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012455 [ALC262_HP_TC_T5735] = {
12456 .mixers = { alc262_hp_t5735_mixer },
12457 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12458 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12459 .dac_nids = alc262_dac_nids,
12460 .hp_nid = 0x03,
12461 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12462 .channel_mode = alc262_modes,
12463 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012464 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012465 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012466 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012467 },
12468 [ALC262_HP_RP5700] = {
12469 .mixers = { alc262_hp_rp5700_mixer },
12470 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12471 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12472 .dac_nids = alc262_dac_nids,
12473 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12474 .channel_mode = alc262_modes,
12475 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012476 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012477 [ALC262_BENQ_ED8] = {
12478 .mixers = { alc262_base_mixer },
12479 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12480 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12481 .dac_nids = alc262_dac_nids,
12482 .hp_nid = 0x03,
12483 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12484 .channel_mode = alc262_modes,
12485 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012486 },
Kailang Yang272a5272007-05-14 11:00:38 +020012487 [ALC262_SONY_ASSAMD] = {
12488 .mixers = { alc262_sony_mixer },
12489 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12490 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12491 .dac_nids = alc262_dac_nids,
12492 .hp_nid = 0x02,
12493 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12494 .channel_mode = alc262_modes,
12495 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012496 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012497 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012498 .init_hook = alc_inithook,
Kailang Yang83c34212007-07-05 11:43:05 +020012499 },
12500 [ALC262_BENQ_T31] = {
12501 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012502 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12503 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012504 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12505 .dac_nids = alc262_dac_nids,
12506 .hp_nid = 0x03,
12507 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12508 .channel_mode = alc262_modes,
12509 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012510 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012511 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012512 .init_hook = alc_inithook,
Kailang Yangea1fb292008-08-26 12:58:38 +020012513 },
Tobin Davisf651b502007-10-26 12:40:47 +020012514 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012515 .mixers = { alc262_ultra_mixer },
12516 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012517 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012518 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12519 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012520 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12521 .channel_mode = alc262_modes,
12522 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012523 .adc_nids = alc262_adc_nids, /* ADC0 */
12524 .capsrc_nids = alc262_capsrc_nids,
12525 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012526 .unsol_event = alc262_ultra_unsol_event,
12527 .init_hook = alc262_ultra_automute,
12528 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012529 [ALC262_LENOVO_3000] = {
12530 .mixers = { alc262_lenovo_3000_mixer },
12531 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012532 alc262_lenovo_3000_unsol_verbs,
12533 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012534 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12535 .dac_nids = alc262_dac_nids,
12536 .hp_nid = 0x03,
12537 .dig_out_nid = ALC262_DIGOUT_NID,
12538 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12539 .channel_mode = alc262_modes,
12540 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012541 .unsol_event = alc_sku_unsol_event,
12542 .setup = alc262_lenovo_3000_setup,
12543 .init_hook = alc_inithook,
Jiang zhe0e31daf2008-03-20 12:12:39 +010012544 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012545 [ALC262_NEC] = {
12546 .mixers = { alc262_nec_mixer },
12547 .init_verbs = { alc262_nec_verbs },
12548 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12549 .dac_nids = alc262_dac_nids,
12550 .hp_nid = 0x03,
12551 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12552 .channel_mode = alc262_modes,
12553 .input_mux = &alc262_capture_source,
12554 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012555 [ALC262_TOSHIBA_S06] = {
12556 .mixers = { alc262_toshiba_s06_mixer },
12557 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12558 alc262_eapd_verbs },
12559 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12560 .capsrc_nids = alc262_dmic_capsrc_nids,
12561 .dac_nids = alc262_dac_nids,
12562 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012563 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012564 .dig_out_nid = ALC262_DIGOUT_NID,
12565 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12566 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012567 .unsol_event = alc_sku_unsol_event,
12568 .setup = alc262_toshiba_s06_setup,
12569 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012570 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012571 [ALC262_TOSHIBA_RX1] = {
12572 .mixers = { alc262_toshiba_rx1_mixer },
12573 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12574 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12575 .dac_nids = alc262_dac_nids,
12576 .hp_nid = 0x03,
12577 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12578 .channel_mode = alc262_modes,
12579 .input_mux = &alc262_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020012580 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012581 .setup = alc262_hippo_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020012582 .init_hook = alc_inithook,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012583 },
Tony Vroonba340e82009-02-02 19:01:30 +000012584 [ALC262_TYAN] = {
12585 .mixers = { alc262_tyan_mixer },
12586 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12587 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12588 .dac_nids = alc262_dac_nids,
12589 .hp_nid = 0x02,
12590 .dig_out_nid = ALC262_DIGOUT_NID,
12591 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12592 .channel_mode = alc262_modes,
12593 .input_mux = &alc262_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020012594 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012595 .setup = alc262_tyan_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020012596 .init_hook = alc_hp_automute,
Tony Vroonba340e82009-02-02 19:01:30 +000012597 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012598};
12599
12600static int patch_alc262(struct hda_codec *codec)
12601{
12602 struct alc_spec *spec;
12603 int board_config;
12604 int err;
12605
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012606 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012607 if (spec == NULL)
12608 return -ENOMEM;
12609
12610 codec->spec = spec;
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020012611
12612 spec->mixer_nid = 0x0b;
12613
Kailang Yangdf694da2005-12-05 19:42:22 +010012614#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012615 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12616 * under-run
12617 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012618 {
12619 int tmp;
12620 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12621 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12622 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12623 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12624 }
12625#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012626 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012627
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012628 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12629
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012630 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12631 alc262_models,
12632 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012633
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012634 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012635 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12636 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012637 board_config = ALC262_AUTO;
12638 }
12639
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012640 if (board_config == ALC262_AUTO) {
12641 alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
12642 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
12643 }
Takashi Iwai18675e42010-09-08 15:55:44 +020012644
Kailang Yangdf694da2005-12-05 19:42:22 +010012645 if (board_config == ALC262_AUTO) {
12646 /* automatic parse from the BIOS config */
12647 err = alc262_parse_auto_config(codec);
12648 if (err < 0) {
12649 alc_free(codec);
12650 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012651 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012652 printk(KERN_INFO
12653 "hda_codec: Cannot set up configuration "
12654 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012655 board_config = ALC262_BASIC;
12656 }
12657 }
12658
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012659 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012660 err = snd_hda_attach_beep_device(codec, 0x1);
12661 if (err < 0) {
12662 alc_free(codec);
12663 return err;
12664 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012665 }
12666
Kailang Yangdf694da2005-12-05 19:42:22 +010012667 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012668 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012669
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012670 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020012671 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020012672 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020012673 alc_remove_invalid_adc_nids(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012674 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012675 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012676 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012677 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012678 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012679
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010012680 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai18675e42010-09-08 15:55:44 +020012681
Takashi Iwai2134ea42008-01-10 16:53:55 +010012682 spec->vmaster_nid = 0x0c;
12683
Kailang Yangdf694da2005-12-05 19:42:22 +010012684 codec->patch_ops = alc_patch_ops;
12685 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012686 spec->init_hook = alc262_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020012687 spec->shutup = alc_eapd_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020012688
12689 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020012690#ifdef CONFIG_SND_HDA_POWER_SAVE
12691 if (!spec->loopback.amplist)
12692 spec->loopback.amplist = alc262_loopbacks;
12693#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012694
Kailang Yangdf694da2005-12-05 19:42:22 +010012695 return 0;
12696}
12697
Kailang Yangdf694da2005-12-05 19:42:22 +010012698/*
Kailang Yanga361d842007-06-05 12:30:55 +020012699 * ALC268 channel source setting (2 channel)
12700 */
12701#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12702#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012703
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012704static const hda_nid_t alc268_dac_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012705 /* front, hp */
12706 0x02, 0x03
12707};
12708
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012709static const hda_nid_t alc268_adc_nids[2] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012710 /* ADC0-1 */
12711 0x08, 0x07
12712};
12713
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012714static const hda_nid_t alc268_adc_nids_alt[1] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012715 /* ADC0 */
12716 0x08
12717};
12718
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020012719static const hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
Takashi Iwaie1406342008-02-11 18:32:32 +010012720
Takashi Iwaia9111322011-05-02 11:30:18 +020012721static const struct snd_kcontrol_new alc268_base_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012722 /* output mixer control */
12723 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12724 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12725 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12726 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012727 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12728 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
12729 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012730 { }
12731};
12732
Takashi Iwaia9111322011-05-02 11:30:18 +020012733static const struct snd_kcontrol_new alc268_toshiba_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012734 /* output mixer control */
12735 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12736 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12737 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010012738 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12739 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
12740 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020012741 { }
12742};
12743
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012744/* bind Beep switches of both NID 0x0f and 0x10 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012745static const struct hda_bind_ctls alc268_bind_beep_sw = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012746 .ops = &snd_hda_bind_sw,
12747 .values = {
12748 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
12749 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
12750 0
12751 },
12752};
12753
Takashi Iwaia9111322011-05-02 11:30:18 +020012754static const struct snd_kcontrol_new alc268_beep_mixer[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012755 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
12756 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
12757 { }
12758};
12759
Takashi Iwaia9111322011-05-02 11:30:18 +020012760static const struct hda_verb alc268_eapd_verbs[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020012761 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
12762 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
12763 { }
12764};
12765
Takashi Iwaid2738092007-08-16 14:59:45 +020012766/* Toshiba specific */
Takashi Iwaia9111322011-05-02 11:30:18 +020012767static const struct hda_verb alc268_toshiba_verbs[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020012768 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12769 { } /* end */
12770};
12771
12772/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020012773/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012774static const struct hda_bind_ctls alc268_acer_bind_master_vol = {
Takashi Iwai6bc96852007-08-17 09:02:12 +020012775 .ops = &snd_hda_bind_vol,
12776 .values = {
12777 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
12778 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
12779 0
12780 },
12781};
12782
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012783static void alc268_acer_setup(struct hda_codec *codec)
Takashi Iwai889c4392007-08-23 18:56:52 +020012784{
12785 struct alc_spec *spec = codec->spec;
Takashi Iwai889c4392007-08-23 18:56:52 +020012786
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012787 spec->autocfg.hp_pins[0] = 0x14;
12788 spec->autocfg.speaker_pins[0] = 0x15;
12789 spec->automute = 1;
12790 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai889c4392007-08-23 18:56:52 +020012791}
12792
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012793#define alc268_acer_master_sw_get alc262_hp_master_sw_get
12794#define alc268_acer_master_sw_put alc262_hp_master_sw_put
Takashi Iwaid2738092007-08-16 14:59:45 +020012795
Takashi Iwaia9111322011-05-02 11:30:18 +020012796static const struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020012797 /* output mixer control */
12798 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12799 {
12800 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12801 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012802 .subdevice = HDA_SUBDEV_NID_FLAG | 0x15,
12803 .info = snd_ctl_boolean_mono_info,
12804 .get = alc268_acer_master_sw_get,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012805 .put = alc268_acer_master_sw_put,
Kailang Yang8ef355d2008-08-26 13:10:22 +020012806 },
12807 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
12808 { }
12809};
12810
Takashi Iwaia9111322011-05-02 11:30:18 +020012811static const struct snd_kcontrol_new alc268_acer_mixer[] = {
Takashi Iwaid2738092007-08-16 14:59:45 +020012812 /* output mixer control */
12813 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12814 {
12815 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12816 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012817 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12818 .info = snd_ctl_boolean_mono_info,
12819 .get = alc268_acer_master_sw_get,
Takashi Iwaid2738092007-08-16 14:59:45 +020012820 .put = alc268_acer_master_sw_put,
Takashi Iwaid2738092007-08-16 14:59:45 +020012821 },
David Henningsson5f99f862011-01-04 15:24:24 +010012822 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12823 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
12824 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020012825 { }
12826};
12827
Takashi Iwaia9111322011-05-02 11:30:18 +020012828static const struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012829 /* output mixer control */
12830 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
12831 {
12832 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12833 .name = "Master Playback Switch",
Takashi Iwai0f0f3912011-04-28 16:26:24 +020012834 .subdevice = HDA_SUBDEV_NID_FLAG | 0x14,
12835 .info = snd_ctl_boolean_mono_info,
12836 .get = alc268_acer_master_sw_get,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012837 .put = alc268_acer_master_sw_put,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012838 },
David Henningsson5f99f862011-01-04 15:24:24 +010012839 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12840 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010012841 { }
12842};
12843
Takashi Iwaia9111322011-05-02 11:30:18 +020012844static const struct hda_verb alc268_acer_aspire_one_verbs[] = {
Kailang Yang8ef355d2008-08-26 13:10:22 +020012845 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
12846 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12847 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12848 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
12849 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
12850 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
12851 { }
12852};
12853
Takashi Iwaia9111322011-05-02 11:30:18 +020012854static const struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012855 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
12856 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020012857 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12858 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010012859 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
12860 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020012861 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12862 { }
12863};
12864
12865/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012866#define alc268_toshiba_setup alc262_hippo_setup
Takashi Iwaid2738092007-08-16 14:59:45 +020012867
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012868static void alc268_acer_lc_setup(struct hda_codec *codec)
12869{
12870 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020012871 spec->autocfg.hp_pins[0] = 0x15;
12872 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020012873 spec->automute = 1;
Takashi Iwai54463a62011-06-13 08:32:06 +020012874 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai21268962011-07-07 15:01:13 +020012875 spec->ext_mic_pin = 0x18;
12876 spec->int_mic_pin = 0x12;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012877 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020012878}
12879
Takashi Iwaia9111322011-05-02 11:30:18 +020012880static const struct snd_kcontrol_new alc268_dell_mixer[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012881 /* output mixer control */
12882 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
12883 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12884 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
12885 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012886 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12887 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012888 { }
12889};
12890
Takashi Iwaia9111322011-05-02 11:30:18 +020012891static const struct hda_verb alc268_dell_verbs[] = {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012892 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12893 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
12894 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012895 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012896 { }
12897};
12898
12899/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012900static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012901{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012902 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012903
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012904 spec->autocfg.hp_pins[0] = 0x15;
12905 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai21268962011-07-07 15:01:13 +020012906 spec->ext_mic_pin = 0x18;
12907 spec->int_mic_pin = 0x19;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012908 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020012909 spec->automute = 1;
12910 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010012911}
12912
Takashi Iwaia9111322011-05-02 11:30:18 +020012913static const struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012914 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12915 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12916 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12917 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
12918 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
12919 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012920 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12921 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012922 { }
12923};
12924
Takashi Iwaia9111322011-05-02 11:30:18 +020012925static const struct hda_verb alc267_quanta_il1_verbs[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012926 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12927 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
12928 { }
12929};
12930
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012931static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012932{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012933 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012934 spec->autocfg.hp_pins[0] = 0x15;
12935 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai21268962011-07-07 15:01:13 +020012936 spec->ext_mic_pin = 0x18;
12937 spec->int_mic_pin = 0x19;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012938 spec->auto_mic = 1;
Takashi Iwaid922b512011-04-28 12:18:53 +020012939 spec->automute = 1;
12940 spec->automute_mode = ALC_AUTOMUTE_PIN;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020012941}
12942
Kailang Yanga361d842007-06-05 12:30:55 +020012943/*
12944 * generic initialization of ADC, input mixers and output mixers
12945 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012946static const struct hda_verb alc268_base_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012947 /* Unmute DAC0-1 and set vol = 0 */
12948 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012949 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020012950
12951 /*
12952 * Set up output mixers (0x0c - 0x0e)
12953 */
12954 /* set vol=0 to output mixers */
12955 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020012956 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
12957
12958 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12959 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12960
12961 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12962 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
12963 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
12964 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12965 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12966 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12967 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12968 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12969
12970 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12971 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12972 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
12973 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012974 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010012975
12976 /* set PCBEEP vol = 0, mute connections */
12977 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12978 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12979 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020012980
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012981 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020012982
Jiang Zhea9b3aa82007-12-20 13:13:13 +010012983 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
12984 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
12985 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
12986 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020012987
Kailang Yanga361d842007-06-05 12:30:55 +020012988 { }
12989};
12990
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020012991/* only for model=test */
12992#ifdef CONFIG_SND_DEBUG
Kailang Yanga361d842007-06-05 12:30:55 +020012993/*
12994 * generic initialization of ADC, input mixers and output mixers
12995 */
Takashi Iwaia9111322011-05-02 11:30:18 +020012996static const struct hda_verb alc268_volume_init_verbs[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020012997 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010012998 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12999 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013000
13001 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13002 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13003 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13004 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13005 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13006
Kailang Yanga361d842007-06-05 12:30:55 +020013007 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013008 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13009 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13010
13011 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013012 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013013 { }
13014};
13015#endif /* CONFIG_SND_DEBUG */
Kailang Yanga361d842007-06-05 12:30:55 +020013016
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013017/* set PCBEEP vol = 0, mute connections */
13018static const struct hda_verb alc268_beep_init_verbs[] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013019 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13020 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13021 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013022 { }
13023};
13024
Takashi Iwaia9111322011-05-02 11:30:18 +020013025static const struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013026 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13027 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13028 { } /* end */
13029};
13030
Takashi Iwaia9111322011-05-02 11:30:18 +020013031static const struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013032 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13033 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013034 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013035 { } /* end */
13036};
13037
Takashi Iwaia9111322011-05-02 11:30:18 +020013038static const struct snd_kcontrol_new alc268_capture_mixer[] = {
Kailang Yanga361d842007-06-05 12:30:55 +020013039 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13040 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13041 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13042 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013043 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013044 { } /* end */
13045};
13046
Takashi Iwaia9111322011-05-02 11:30:18 +020013047static const struct hda_input_mux alc268_capture_source = {
Kailang Yanga361d842007-06-05 12:30:55 +020013048 .num_items = 4,
13049 .items = {
13050 { "Mic", 0x0 },
13051 { "Front Mic", 0x1 },
13052 { "Line", 0x2 },
13053 { "CD", 0x3 },
13054 },
13055};
13056
Takashi Iwaia9111322011-05-02 11:30:18 +020013057static const struct hda_input_mux alc268_acer_capture_source = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013058 .num_items = 3,
13059 .items = {
13060 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013061 { "Internal Mic", 0x1 },
13062 { "Line", 0x2 },
13063 },
13064};
13065
Takashi Iwaia9111322011-05-02 11:30:18 +020013066static const struct hda_input_mux alc268_acer_dmic_capture_source = {
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013067 .num_items = 3,
13068 .items = {
13069 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013070 { "Internal Mic", 0x6 },
13071 { "Line", 0x2 },
13072 },
13073};
13074
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013075#ifdef CONFIG_SND_DEBUG
Takashi Iwaia9111322011-05-02 11:30:18 +020013076static const struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013077 /* Volume widgets */
13078 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13079 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13080 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13081 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13082 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13083 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13084 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13085 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13086 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13087 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13088 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13089 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13090 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013091 /* The below appears problematic on some hardwares */
13092 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013093 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13094 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13095 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13096 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13097
13098 /* Modes for retasking pin widgets */
13099 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13100 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13101 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13102 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13103
13104 /* Controls for GPIO pins, assuming they are configured as outputs */
13105 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13106 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13107 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13108 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13109
13110 /* Switches to allow the digital SPDIF output pin to be enabled.
13111 * The ALC268 does not have an SPDIF input.
13112 */
13113 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13114
13115 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13116 * this output to turn on an external amplifier.
13117 */
13118 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13119 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13120
13121 { } /* end */
13122};
13123#endif
13124
Kailang Yanga361d842007-06-05 12:30:55 +020013125/* create input playback/capture controls for the given pin */
13126static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13127 const char *ctlname, int idx)
13128{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013129 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013130 int err;
13131
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013132 switch (nid) {
13133 case 0x14:
13134 case 0x16:
13135 dac = 0x02;
13136 break;
13137 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013138 case 0x1a: /* ALC259/269 only */
13139 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013140 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013141 dac = 0x03;
13142 break;
13143 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013144 snd_printd(KERN_WARNING "hda_codec: "
13145 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013146 return 0;
13147 }
13148 if (spec->multiout.dac_nids[0] != dac &&
13149 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013150 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013151 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013152 HDA_OUTPUT));
13153 if (err < 0)
13154 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020013155 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013156 }
13157
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013158 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013159 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013160 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013161 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013162 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013163 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013164 if (err < 0)
13165 return err;
13166 return 0;
13167}
13168
13169/* add playback controls from the parsed DAC table */
13170static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13171 const struct auto_pin_cfg *cfg)
13172{
13173 hda_nid_t nid;
13174 int err;
13175
Kailang Yanga361d842007-06-05 12:30:55 +020013176 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013177
13178 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013179 if (nid) {
13180 const char *name;
Takashi Iwai2e925dd2011-06-24 11:27:22 +020013181 int index;
13182 name = alc_get_line_out_pfx(spec, 0, true, &index);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013183 err = alc268_new_analog_output(spec, nid, name, 0);
13184 if (err < 0)
13185 return err;
13186 }
Kailang Yanga361d842007-06-05 12:30:55 +020013187
13188 nid = cfg->speaker_pins[0];
13189 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013190 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013191 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13192 if (err < 0)
13193 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013194 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013195 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13196 if (err < 0)
13197 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013198 }
13199 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013200 if (nid) {
13201 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13202 if (err < 0)
13203 return err;
13204 }
Kailang Yanga361d842007-06-05 12:30:55 +020013205
13206 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13207 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013208 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013209 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013210 if (err < 0)
13211 return err;
13212 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013213 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013214}
13215
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013216static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13217 hda_nid_t nid, int pin_type)
13218{
13219 int idx;
13220
13221 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai4f574b72011-06-27 16:17:07 +020013222 if (snd_hda_get_conn_list(codec, nid, NULL) <= 1)
13223 return;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013224 if (nid == 0x14 || nid == 0x16)
13225 idx = 0;
13226 else
13227 idx = 1;
13228 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13229}
13230
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013231static void alc268_auto_init_dac(struct hda_codec *codec, hda_nid_t nid)
13232{
13233 if (!nid)
13234 return;
13235 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai7ec9c6c2011-06-27 15:53:38 +020013236 AMP_OUT_ZERO);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013237}
13238
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013239static void alc268_auto_init_multi_out(struct hda_codec *codec)
13240{
13241 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013242 int i;
13243
13244 for (i = 0; i < spec->autocfg.line_outs; i++) {
13245 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013246 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13247 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13248 }
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013249 /* mute DACs */
13250 for (i = 0; i < spec->multiout.num_dacs; i++)
13251 alc268_auto_init_dac(codec, spec->multiout.dac_nids[i]);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013252}
13253
13254static void alc268_auto_init_hp_out(struct hda_codec *codec)
13255{
13256 struct alc_spec *spec = codec->spec;
13257 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013258 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013259
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013260 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13261 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013262 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013263 }
13264 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13265 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013266 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013267 }
13268 if (spec->autocfg.mono_out_pin)
13269 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13270 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013271 /* mute DACs */
13272 alc268_auto_init_dac(codec, spec->multiout.hp_nid);
13273 for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++)
13274 alc268_auto_init_dac(codec, spec->multiout.extra_out_nid[i]);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013275}
13276
Kailang Yanga361d842007-06-05 12:30:55 +020013277static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13278{
13279 struct alc_spec *spec = codec->spec;
13280 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13281 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13282 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13283 unsigned int dac_vol1, dac_vol2;
13284
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013285 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013286 snd_hda_codec_write(codec, speaker_nid, 0,
13287 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013288 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013289 snd_hda_codec_write(codec, 0x0f, 0,
13290 AC_VERB_SET_AMP_GAIN_MUTE,
13291 AMP_IN_UNMUTE(1));
13292 snd_hda_codec_write(codec, 0x10, 0,
13293 AC_VERB_SET_AMP_GAIN_MUTE,
13294 AMP_IN_UNMUTE(1));
13295 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013296 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013297 snd_hda_codec_write(codec, 0x0f, 0,
13298 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13299 snd_hda_codec_write(codec, 0x10, 0,
13300 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13301 }
13302
13303 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013304 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013305 dac_vol2 = AMP_OUT_ZERO;
13306 else if (line_nid == 0x15)
13307 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013308 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013309 dac_vol2 = AMP_OUT_ZERO;
13310 else if (hp_nid == 0x15)
13311 dac_vol1 = AMP_OUT_ZERO;
13312 if (line_nid != 0x16 || hp_nid != 0x16 ||
13313 spec->autocfg.line_out_pins[1] != 0x16 ||
13314 spec->autocfg.line_out_pins[2] != 0x16)
13315 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13316
13317 snd_hda_codec_write(codec, 0x02, 0,
13318 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13319 snd_hda_codec_write(codec, 0x03, 0,
13320 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13321}
13322
Kailang Yanga361d842007-06-05 12:30:55 +020013323/*
13324 * BIOS auto configuration
13325 */
13326static int alc268_parse_auto_config(struct hda_codec *codec)
13327{
13328 struct alc_spec *spec = codec->spec;
13329 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013330 static const hda_nid_t alc268_ignore[] = { 0 };
Kailang Yanga361d842007-06-05 12:30:55 +020013331
13332 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13333 alc268_ignore);
13334 if (err < 0)
13335 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013336 if (!spec->autocfg.line_outs) {
13337 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13338 spec->multiout.max_channels = 2;
13339 spec->no_analog = 1;
13340 goto dig_only;
13341 }
Kailang Yanga361d842007-06-05 12:30:55 +020013342 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013343 }
Kailang Yanga361d842007-06-05 12:30:55 +020013344 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13345 if (err < 0)
13346 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020013347 err = alc_auto_create_input_ctls(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013348 if (err < 0)
13349 return err;
13350
13351 spec->multiout.max_channels = 2;
13352
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013353 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013354 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013355 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013356 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013357 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013358
Takashi Iwai4f574b72011-06-27 16:17:07 +020013359 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
Takashi Iwaid88897e2008-10-31 15:01:37 +010013360 add_mixer(spec, alc268_beep_mixer);
Takashi Iwai4f574b72011-06-27 16:17:07 +020013361 add_verb(spec, alc268_beep_init_verbs);
13362 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013363
Takashi Iwai776e1842007-08-29 15:07:11 +020013364 err = alc_auto_add_mic_boost(codec);
13365 if (err < 0)
13366 return err;
13367
Takashi Iwai21268962011-07-07 15:01:13 +020013368 alc_remove_invalid_adc_nids(codec);
13369
Kailang Yang6227cdc2010-02-25 08:36:52 +010013370 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai21268962011-07-07 15:01:13 +020013371 alc_auto_check_switches(codec);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013372
Kailang Yanga361d842007-06-05 12:30:55 +020013373 return 1;
13374}
13375
Kailang Yanga361d842007-06-05 12:30:55 +020013376/* init callback for auto-configuration model -- overriding the default init */
13377static void alc268_auto_init(struct hda_codec *codec)
13378{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013379 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013380 alc268_auto_init_multi_out(codec);
13381 alc268_auto_init_hp_out(codec);
13382 alc268_auto_init_mono_speaker_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020013383 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020013384 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013385 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013386 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013387 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013388}
13389
13390/*
13391 * configuration and preset
13392 */
Takashi Iwaiea734962011-01-17 11:29:34 +010013393static const char * const alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013394 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013395 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013396 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013397 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013398 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013399 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013400 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013401 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013402#ifdef CONFIG_SND_DEBUG
13403 [ALC268_TEST] = "test",
13404#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013405 [ALC268_AUTO] = "auto",
13406};
13407
Takashi Iwaia9111322011-05-02 11:30:18 +020013408static const struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013409 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013410 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013411 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013412 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013413 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013414 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13415 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013416 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chen0a1896b2011-06-06 18:55:34 -040013417 SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron 910", ALC268_AUTO),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013418 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13419 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013420 /* almost compatible with toshiba but with optional digital outs;
13421 * auto-probing seems working fine
13422 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013423 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013424 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013425 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013426 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013427 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013428 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013429 {}
13430};
13431
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013432/* Toshiba laptops have no unique PCI SSID but only codec SSID */
Takashi Iwaia9111322011-05-02 11:30:18 +020013433static const struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013434 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13435 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13436 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13437 ALC268_TOSHIBA),
13438 {}
13439};
13440
Takashi Iwaia9111322011-05-02 11:30:18 +020013441static const struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013442 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013443 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13444 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013445 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13446 alc267_quanta_il1_verbs },
13447 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13448 .dac_nids = alc268_dac_nids,
13449 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13450 .adc_nids = alc268_adc_nids_alt,
13451 .hp_nid = 0x03,
13452 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13453 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013454 .unsol_event = alc_sku_unsol_event,
13455 .setup = alc267_quanta_il1_setup,
13456 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013457 },
Kailang Yanga361d842007-06-05 12:30:55 +020013458 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013459 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13460 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013461 .init_verbs = { alc268_base_init_verbs },
13462 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13463 .dac_nids = alc268_dac_nids,
13464 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13465 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013466 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013467 .hp_nid = 0x03,
13468 .dig_out_nid = ALC268_DIGOUT_NID,
13469 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13470 .channel_mode = alc268_modes,
13471 .input_mux = &alc268_capture_source,
13472 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013473 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013474 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013475 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013476 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13477 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013478 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13479 .dac_nids = alc268_dac_nids,
13480 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13481 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013482 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013483 .hp_nid = 0x03,
13484 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13485 .channel_mode = alc268_modes,
13486 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013487 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013488 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013489 .init_hook = alc_inithook,
Takashi Iwaid2738092007-08-16 14:59:45 +020013490 },
13491 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013492 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013493 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013494 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13495 alc268_acer_verbs },
13496 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13497 .dac_nids = alc268_dac_nids,
13498 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13499 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013500 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013501 .hp_nid = 0x02,
13502 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13503 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013504 .input_mux = &alc268_acer_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013505 .unsol_event = alc_sku_unsol_event,
13506 .setup = alc268_acer_setup,
13507 .init_hook = alc_inithook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013508 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013509 [ALC268_ACER_DMIC] = {
13510 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13511 alc268_beep_mixer },
13512 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13513 alc268_acer_verbs },
13514 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13515 .dac_nids = alc268_dac_nids,
13516 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13517 .adc_nids = alc268_adc_nids_alt,
13518 .capsrc_nids = alc268_capsrc_nids,
13519 .hp_nid = 0x02,
13520 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13521 .channel_mode = alc268_modes,
13522 .input_mux = &alc268_acer_dmic_capture_source,
Takashi Iwai0f0f3912011-04-28 16:26:24 +020013523 .unsol_event = alc_sku_unsol_event,
13524 .setup = alc268_acer_setup,
13525 .init_hook = alc_inithook,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013526 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013527 [ALC268_ACER_ASPIRE_ONE] = {
13528 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013529 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013530 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013531 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13532 alc268_acer_aspire_one_verbs },
13533 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13534 .dac_nids = alc268_dac_nids,
13535 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13536 .adc_nids = alc268_adc_nids_alt,
13537 .capsrc_nids = alc268_capsrc_nids,
13538 .hp_nid = 0x03,
13539 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13540 .channel_mode = alc268_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013541 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013542 .setup = alc268_acer_lc_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013543 .init_hook = alc_inithook,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013544 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013545 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013546 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13547 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013548 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13549 alc268_dell_verbs },
13550 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13551 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013552 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13553 .adc_nids = alc268_adc_nids_alt,
13554 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013555 .hp_nid = 0x02,
13556 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13557 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013558 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013559 .setup = alc268_dell_setup,
13560 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013561 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013562 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013563 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13564 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013565 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13566 alc268_toshiba_verbs },
13567 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13568 .dac_nids = alc268_dac_nids,
13569 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13570 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013571 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013572 .hp_nid = 0x03,
13573 .dig_out_nid = ALC268_DIGOUT_NID,
13574 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13575 .channel_mode = alc268_modes,
13576 .input_mux = &alc268_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020013577 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013578 .setup = alc268_toshiba_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020013579 .init_hook = alc_inithook,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013580 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013581#ifdef CONFIG_SND_DEBUG
13582 [ALC268_TEST] = {
13583 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13584 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013585 alc268_volume_init_verbs,
13586 alc268_beep_init_verbs },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013587 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13588 .dac_nids = alc268_dac_nids,
13589 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13590 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013591 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013592 .hp_nid = 0x03,
13593 .dig_out_nid = ALC268_DIGOUT_NID,
13594 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13595 .channel_mode = alc268_modes,
13596 .input_mux = &alc268_capture_source,
13597 },
13598#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013599};
13600
13601static int patch_alc268(struct hda_codec *codec)
13602{
13603 struct alc_spec *spec;
13604 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013605 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013606
Julia Lawallef86f582009-12-19 08:18:03 +010013607 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013608 if (spec == NULL)
13609 return -ENOMEM;
13610
13611 codec->spec = spec;
13612
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020013613 /* ALC268 has no aa-loopback mixer */
13614
Kailang Yanga361d842007-06-05 12:30:55 +020013615 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13616 alc268_models,
13617 alc268_cfg_tbl);
13618
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013619 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13620 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013621 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013622
Kailang Yanga361d842007-06-05 12:30:55 +020013623 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013624 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13625 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013626 board_config = ALC268_AUTO;
13627 }
13628
13629 if (board_config == ALC268_AUTO) {
13630 /* automatic parse from the BIOS config */
13631 err = alc268_parse_auto_config(codec);
13632 if (err < 0) {
13633 alc_free(codec);
13634 return err;
13635 } else if (!err) {
13636 printk(KERN_INFO
13637 "hda_codec: Cannot set up configuration "
13638 "from BIOS. Using base mode...\n");
13639 board_config = ALC268_3ST;
13640 }
13641 }
13642
13643 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013644 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013645
Takashi Iwai22971e32009-02-10 11:56:44 +010013646 has_beep = 0;
13647 for (i = 0; i < spec->num_mixers; i++) {
13648 if (spec->mixers[i] == alc268_beep_mixer) {
13649 has_beep = 1;
13650 break;
13651 }
13652 }
13653
13654 if (has_beep) {
13655 err = snd_hda_attach_beep_device(codec, 0x1);
13656 if (err < 0) {
13657 alc_free(codec);
13658 return err;
13659 }
13660 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13661 /* override the amp caps for beep generator */
13662 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013663 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13664 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13665 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13666 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013667 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013668
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013669 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020013670 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020013671 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020013672 alc_remove_invalid_adc_nids(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013673 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010013674
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020013675 if (!spec->cap_mixer && !spec->no_analog)
13676 set_capture_mixer(codec);
13677
Takashi Iwai2134ea42008-01-10 16:53:55 +010013678 spec->vmaster_nid = 0x02;
13679
Kailang Yanga361d842007-06-05 12:30:55 +020013680 codec->patch_ops = alc_patch_ops;
13681 if (board_config == ALC268_AUTO)
13682 spec->init_hook = alc268_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020013683 spec->shutup = alc_eapd_shutup;
Kailang Yangea1fb292008-08-26 12:58:38 +020013684
Kailang Yangbf1b0222010-10-21 08:49:56 +020013685 alc_init_jacks(codec);
13686
Kailang Yanga361d842007-06-05 12:30:55 +020013687 return 0;
13688}
13689
13690/*
Kailang Yangf6a92242007-12-13 16:52:54 +010013691 * ALC269 channel source setting (2 channel)
13692 */
13693#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
13694
13695#define alc269_dac_nids alc260_dac_nids
13696
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013697static const hda_nid_t alc269_adc_nids[1] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010013698 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020013699 0x08,
13700};
13701
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013702static const hda_nid_t alc269_capsrc_nids[1] = {
Takashi Iwaie01bf502008-08-21 16:25:07 +020013703 0x23,
13704};
13705
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013706static const hda_nid_t alc269vb_adc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013707 /* ADC1 */
13708 0x09,
13709};
13710
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020013711static const hda_nid_t alc269vb_capsrc_nids[1] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013712 0x22,
13713};
13714
Kailang Yangf6a92242007-12-13 16:52:54 +010013715#define alc269_modes alc260_modes
13716#define alc269_capture_source alc880_lg_lw_capture_source
13717
Takashi Iwaia9111322011-05-02 11:30:18 +020013718static const struct snd_kcontrol_new alc269_base_mixer[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010013719 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13720 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13721 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
13722 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
13723 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13724 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013725 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010013726 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13727 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013728 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010013729 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13730 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
13731 { } /* end */
13732};
13733
Takashi Iwaia9111322011-05-02 11:30:18 +020013734static const struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013735 /* output mixer control */
13736 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13737 {
13738 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13739 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013740 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020013741 .info = snd_hda_mixer_amp_switch_info,
13742 .get = snd_hda_mixer_amp_switch_get,
13743 .put = alc268_acer_master_sw_put,
13744 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13745 },
13746 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13747 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013748 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013749 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13750 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013751 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020013752 { }
13753};
13754
Takashi Iwaia9111322011-05-02 11:30:18 +020013755static const struct snd_kcontrol_new alc269_lifebook_mixer[] = {
Tony Vroon64154832008-11-06 15:08:49 +000013756 /* output mixer control */
13757 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13758 {
13759 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13760 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013761 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000013762 .info = snd_hda_mixer_amp_switch_info,
13763 .get = snd_hda_mixer_amp_switch_get,
13764 .put = alc268_acer_master_sw_put,
13765 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13766 },
13767 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
13768 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013769 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013770 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
13771 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013772 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013773 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
13774 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013775 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000013776 { }
13777};
13778
Takashi Iwaia9111322011-05-02 11:30:18 +020013779static const struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020013780 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013781 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020013782 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010013783 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020013784 { } /* end */
13785};
13786
Takashi Iwaia9111322011-05-02 11:30:18 +020013787static const struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013788 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13789 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13790 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
13791 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13792 { } /* end */
13793};
13794
Takashi Iwaia9111322011-05-02 11:30:18 +020013795static const struct snd_kcontrol_new alc269_asus_mixer[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020013796 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13797 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
13798 { } /* end */
13799};
13800
Kailang Yangf6a92242007-12-13 16:52:54 +010013801/* capture mixer elements */
Takashi Iwaia9111322011-05-02 11:30:18 +020013802static const struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013803 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13804 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013805 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13806 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013807 { } /* end */
13808};
13809
Takashi Iwaia9111322011-05-02 11:30:18 +020013810static const struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020013811 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
13812 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013813 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010013814 { } /* end */
13815};
13816
Takashi Iwaia9111322011-05-02 11:30:18 +020013817static const struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013818 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13819 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013820 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13821 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013822 { } /* end */
13823};
13824
Takashi Iwaia9111322011-05-02 11:30:18 +020013825static const struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013826 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
13827 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013828 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010013829 { } /* end */
13830};
13831
Takashi Iwai26f5df22008-11-03 17:39:46 +010013832/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010013833#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020013834
Takashi Iwaia9111322011-05-02 11:30:18 +020013835static const struct hda_verb alc269_quanta_fl1_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013836 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13837 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13838 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13839 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13840 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13841 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13842 { }
13843};
13844
Takashi Iwaia9111322011-05-02 11:30:18 +020013845static const struct hda_verb alc269_lifebook_verbs[] = {
Tony Vroon64154832008-11-06 15:08:49 +000013846 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13847 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
13848 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13849 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13850 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13851 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13852 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13853 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13854 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13855 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13856 { }
13857};
13858
Kailang Yang60db6b52008-08-26 13:13:00 +020013859/* toggle speaker-output according to the hp-jack state */
13860static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
13861{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013862 alc_hp_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013863
13864 snd_hda_codec_write(codec, 0x20, 0,
13865 AC_VERB_SET_COEF_INDEX, 0x0c);
13866 snd_hda_codec_write(codec, 0x20, 0,
13867 AC_VERB_SET_PROC_COEF, 0x680);
13868
13869 snd_hda_codec_write(codec, 0x20, 0,
13870 AC_VERB_SET_COEF_INDEX, 0x0c);
13871 snd_hda_codec_write(codec, 0x20, 0,
13872 AC_VERB_SET_PROC_COEF, 0x480);
13873}
13874
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013875#define alc269_lifebook_speaker_automute \
13876 alc269_quanta_fl1_speaker_automute
Tony Vroon64154832008-11-06 15:08:49 +000013877
Tony Vroon64154832008-11-06 15:08:49 +000013878static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
13879{
13880 unsigned int present_laptop;
13881 unsigned int present_dock;
13882
Wu Fengguang864f92b2009-11-18 12:38:02 +080013883 present_laptop = snd_hda_jack_detect(codec, 0x18);
13884 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000013885
13886 /* Laptop mic port overrides dock mic port, design decision */
13887 if (present_dock)
13888 snd_hda_codec_write(codec, 0x23, 0,
13889 AC_VERB_SET_CONNECT_SEL, 0x3);
13890 if (present_laptop)
13891 snd_hda_codec_write(codec, 0x23, 0,
13892 AC_VERB_SET_CONNECT_SEL, 0x0);
13893 if (!present_dock && !present_laptop)
13894 snd_hda_codec_write(codec, 0x23, 0,
13895 AC_VERB_SET_CONNECT_SEL, 0x1);
13896}
13897
Kailang Yang60db6b52008-08-26 13:13:00 +020013898static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
13899 unsigned int res)
13900{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013901 switch (res >> 26) {
13902 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020013903 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013904 break;
13905 case ALC880_MIC_EVENT:
13906 alc_mic_automute(codec);
13907 break;
13908 }
Kailang Yang60db6b52008-08-26 13:13:00 +020013909}
13910
Tony Vroon64154832008-11-06 15:08:49 +000013911static void alc269_lifebook_unsol_event(struct hda_codec *codec,
13912 unsigned int res)
13913{
13914 if ((res >> 26) == ALC880_HP_EVENT)
13915 alc269_lifebook_speaker_automute(codec);
13916 if ((res >> 26) == ALC880_MIC_EVENT)
13917 alc269_lifebook_mic_autoswitch(codec);
13918}
13919
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013920static void alc269_quanta_fl1_setup(struct hda_codec *codec)
13921{
13922 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010013923 spec->autocfg.hp_pins[0] = 0x15;
13924 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013925 spec->automute_mixer_nid[0] = 0x0c;
13926 spec->automute = 1;
13927 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020013928 spec->ext_mic_pin = 0x18;
13929 spec->int_mic_pin = 0x19;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013930 spec->auto_mic = 1;
13931}
13932
Kailang Yang60db6b52008-08-26 13:13:00 +020013933static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
13934{
13935 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013936 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020013937}
13938
Takashi Iwai3b8510c2011-04-28 14:03:24 +020013939static void alc269_lifebook_setup(struct hda_codec *codec)
13940{
13941 struct alc_spec *spec = codec->spec;
13942 spec->autocfg.hp_pins[0] = 0x15;
13943 spec->autocfg.hp_pins[1] = 0x1a;
13944 spec->autocfg.speaker_pins[0] = 0x14;
13945 spec->automute_mixer_nid[0] = 0x0c;
13946 spec->automute = 1;
13947 spec->automute_mode = ALC_AUTOMUTE_MIXER;
13948}
13949
Tony Vroon64154832008-11-06 15:08:49 +000013950static void alc269_lifebook_init_hook(struct hda_codec *codec)
13951{
13952 alc269_lifebook_speaker_automute(codec);
13953 alc269_lifebook_mic_autoswitch(codec);
13954}
13955
Takashi Iwaia9111322011-05-02 11:30:18 +020013956static const struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013957 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13958 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
13959 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13960 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13961 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13962 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13963 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13964 {}
13965};
13966
Takashi Iwaia9111322011-05-02 11:30:18 +020013967static const struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020013968 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
13969 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
13970 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13971 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
13972 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13973 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13974 {}
13975};
13976
Takashi Iwaia9111322011-05-02 11:30:18 +020013977static const struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013978 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13979 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
13980 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13981 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13982 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13983 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13984 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13985 {}
13986};
13987
Takashi Iwaia9111322011-05-02 11:30:18 +020013988static const struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010013989 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
13990 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
13991 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
13992 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
13993 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13994 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13995 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
13996 {}
13997};
13998
Takashi Iwaia9111322011-05-02 11:30:18 +020013999static const struct hda_verb alc271_acer_dmic_verbs[] = {
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014000 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14001 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14002 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14003 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14004 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14005 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14006 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14007 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14008 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14009 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14010 { }
14011};
14012
Kailang Yang226b1ec2010-04-09 11:01:20 +020014013static void alc269_laptop_amic_setup(struct hda_codec *codec)
14014{
14015 struct alc_spec *spec = codec->spec;
14016 spec->autocfg.hp_pins[0] = 0x15;
14017 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014018 spec->automute_mixer_nid[0] = 0x0c;
14019 spec->automute = 1;
14020 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020014021 spec->ext_mic_pin = 0x18;
14022 spec->int_mic_pin = 0x19;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014023 spec->auto_mic = 1;
14024}
14025
Kailang Yang84898e82010-02-04 14:16:14 +010014026static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014027{
14028 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014029 spec->autocfg.hp_pins[0] = 0x15;
14030 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014031 spec->automute_mixer_nid[0] = 0x0c;
14032 spec->automute = 1;
14033 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020014034 spec->ext_mic_pin = 0x18;
14035 spec->int_mic_pin = 0x12;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014036 spec->auto_mic = 1;
14037}
14038
Kailang Yang226b1ec2010-04-09 11:01:20 +020014039static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014040{
14041 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014042 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014043 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014044 spec->automute_mixer_nid[0] = 0x0c;
14045 spec->automute = 1;
14046 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020014047 spec->ext_mic_pin = 0x18;
14048 spec->int_mic_pin = 0x19;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014049 spec->auto_mic = 1;
14050}
14051
Kailang Yang226b1ec2010-04-09 11:01:20 +020014052static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14053{
14054 struct alc_spec *spec = codec->spec;
14055 spec->autocfg.hp_pins[0] = 0x21;
14056 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014057 spec->automute_mixer_nid[0] = 0x0c;
14058 spec->automute = 1;
14059 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020014060 spec->ext_mic_pin = 0x18;
14061 spec->int_mic_pin = 0x12;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014062 spec->auto_mic = 1;
14063}
14064
Kailang Yangf6a92242007-12-13 16:52:54 +010014065/*
14066 * generic initialization of ADC, input mixers and output mixers
14067 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014068static const struct hda_verb alc269_init_verbs[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014069 /*
14070 * Unmute ADC0 and set the default input to mic-in
14071 */
Kailang Yang84898e82010-02-04 14:16:14 +010014072 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014073
14074 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014075 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014076 */
14077 /* set vol=0 to output mixers */
14078 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14079 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14080
14081 /* set up input amps for analog loopback */
14082 /* Amp Indices: DAC = 0, mixer = 1 */
14083 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14084 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14085 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14086 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14087 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14088 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14089
14090 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14091 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14092 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14093 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14094 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14095 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14096 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14097
14098 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14099 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014100
Kailang Yang84898e82010-02-04 14:16:14 +010014101 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014102 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14103 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014104 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014105
14106 /* set EAPD */
14107 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014108 { }
14109};
14110
Takashi Iwaia9111322011-05-02 11:30:18 +020014111static const struct hda_verb alc269vb_init_verbs[] = {
Kailang Yang84898e82010-02-04 14:16:14 +010014112 /*
14113 * Unmute ADC0 and set the default input to mic-in
14114 */
14115 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14116
14117 /*
14118 * Set up output mixers (0x02 - 0x03)
14119 */
14120 /* set vol=0 to output mixers */
14121 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14122 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14123
14124 /* set up input amps for analog loopback */
14125 /* Amp Indices: DAC = 0, mixer = 1 */
14126 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14127 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14128 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14129 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14130 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14131 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14132
14133 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14134 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14135 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14136 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14137 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14138 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14139 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14140
14141 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14142 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14143
14144 /* FIXME: use Mux-type input source selection */
14145 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14146 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14147 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14148
14149 /* set EAPD */
14150 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014151 { }
14152};
14153
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014154#define alc269_auto_create_multi_out_ctls \
14155 alc268_auto_create_multi_out_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014156
14157#ifdef CONFIG_SND_HDA_POWER_SAVE
14158#define alc269_loopbacks alc880_loopbacks
14159#endif
14160
Takashi Iwaia9111322011-05-02 11:30:18 +020014161static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014162 .substreams = 1,
14163 .channels_min = 2,
14164 .channels_max = 8,
14165 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14166 /* NID is set in alc_build_pcms */
14167 .ops = {
Takashi Iwaic2d986b2011-07-06 18:30:08 +020014168 .open = alc_playback_pcm_open,
14169 .prepare = alc_playback_pcm_prepare,
14170 .cleanup = alc_playback_pcm_cleanup
Takashi Iwaif03d3112009-03-05 14:18:16 +010014171 },
14172};
14173
Takashi Iwaia9111322011-05-02 11:30:18 +020014174static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014175 .substreams = 1,
14176 .channels_min = 2,
14177 .channels_max = 2,
14178 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14179 /* NID is set in alc_build_pcms */
14180};
14181
Takashi Iwaiad358792010-03-30 18:00:59 +020014182#ifdef CONFIG_SND_HDA_POWER_SAVE
14183static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14184{
14185 switch (codec->subsystem_id) {
14186 case 0x103c1586:
14187 return 1;
14188 }
14189 return 0;
14190}
14191
14192static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14193{
14194 /* update mute-LED according to the speaker mute state */
14195 if (nid == 0x01 || nid == 0x14) {
14196 int pinval;
14197 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14198 HDA_AMP_MUTE)
14199 pinval = 0x24;
14200 else
14201 pinval = 0x20;
14202 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014203 snd_hda_codec_update_cache(codec, 0x19, 0,
14204 AC_VERB_SET_PIN_WIDGET_CONTROL,
14205 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014206 }
14207 return alc_check_power_status(codec, nid);
14208}
14209#endif /* CONFIG_SND_HDA_POWER_SAVE */
14210
Takashi Iwaid433a672010-09-20 15:11:54 +020014211/* different alc269-variants */
14212enum {
Kailang Yangb6878572011-07-06 09:51:29 +020014213 ALC269_TYPE_ALC269VA,
Kailang Yang48c88e82010-11-23 08:56:16 +010014214 ALC269_TYPE_ALC269VB,
Kailang Yangb6878572011-07-06 09:51:29 +020014215 ALC269_TYPE_ALC269VC,
Takashi Iwaid433a672010-09-20 15:11:54 +020014216};
14217
Kailang Yangf6a92242007-12-13 16:52:54 +010014218/*
14219 * BIOS auto configuration
14220 */
14221static int alc269_parse_auto_config(struct hda_codec *codec)
14222{
14223 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014224 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020014225 static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
Kailang Yangf6a92242007-12-13 16:52:54 +010014226
14227 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14228 alc269_ignore);
14229 if (err < 0)
14230 return err;
14231
14232 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14233 if (err < 0)
14234 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020014235 err = alc_auto_create_input_ctls(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014236 if (err < 0)
14237 return err;
14238
14239 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14240
Takashi Iwai757899a2010-07-30 10:48:14 +020014241 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014242
Takashi Iwai603c4012008-07-30 15:01:44 +020014243 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014244 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014245
Takashi Iwai21268962011-07-07 15:01:13 +020014246 alc_remove_invalid_adc_nids(codec);
14247
Kailang Yangb6878572011-07-06 09:51:29 +020014248 if (spec->codec_variant != ALC269_TYPE_ALC269VA)
Kailang Yang6227cdc2010-02-25 08:36:52 +010014249 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020014250 else
Kailang Yang6227cdc2010-02-25 08:36:52 +010014251 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai21268962011-07-07 15:01:13 +020014252 alc_auto_check_switches(codec);
Takashi Iwai66946352010-03-29 17:21:45 +020014253
Kailang Yangf6a92242007-12-13 16:52:54 +010014254 err = alc_auto_add_mic_boost(codec);
14255 if (err < 0)
14256 return err;
14257
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014258 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014259 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014260
Kailang Yangf6a92242007-12-13 16:52:54 +010014261 return 1;
14262}
14263
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014264#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14265#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014266
14267
14268/* init callback for auto-configuration model -- overriding the default init */
14269static void alc269_auto_init(struct hda_codec *codec)
14270{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014271 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014272 alc269_auto_init_multi_out(codec);
14273 alc269_auto_init_hp_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020014274 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020014275 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014276 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014277 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014278 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014279}
14280
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014281static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14282{
14283 int val = alc_read_coef_idx(codec, 0x04);
14284 if (power_up)
14285 val |= 1 << 11;
14286 else
14287 val &= ~(1 << 11);
14288 alc_write_coef_idx(codec, 0x04, val);
14289}
14290
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014291static void alc269_shutup(struct hda_codec *codec)
Kailang Yang977ddd62010-09-15 10:02:29 +020014292{
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014293 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14294 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014295 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014296 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014297 msleep(150);
14298 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014299}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014300
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014301#ifdef SND_HDA_NEEDS_RESUME
Kailang Yang977ddd62010-09-15 10:02:29 +020014302static int alc269_resume(struct hda_codec *codec)
14303{
Kailang Yang977ddd62010-09-15 10:02:29 +020014304 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014305 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014306 msleep(150);
14307 }
14308
14309 codec->patch_ops.init(codec);
14310
14311 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014312 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014313 msleep(200);
14314 }
14315
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014316 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14317 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014318
14319 snd_hda_codec_resume_amp(codec);
14320 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014321 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014322 return 0;
14323}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014324#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014325
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014326static void alc269_fixup_hweq(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014327 const struct alc_fixup *fix, int action)
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014328{
14329 int coef;
14330
Takashi Iwai58701122011-01-13 15:41:45 +010014331 if (action != ALC_FIXUP_ACT_INIT)
Takashi Iwai9fb1ef22011-01-13 14:40:43 +010014332 return;
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014333 coef = alc_read_coef_idx(codec, 0x1e);
14334 alc_write_coef_idx(codec, 0x1e, coef | 0x80);
14335}
14336
Takashi Iwai6981d182011-04-15 10:11:12 +020014337static void alc271_fixup_dmic(struct hda_codec *codec,
14338 const struct alc_fixup *fix, int action)
14339{
Takashi Iwaia9111322011-05-02 11:30:18 +020014340 static const struct hda_verb verbs[] = {
Takashi Iwai6981d182011-04-15 10:11:12 +020014341 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14342 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14343 {}
14344 };
14345 unsigned int cfg;
14346
14347 if (strcmp(codec->chip_name, "ALC271X"))
14348 return;
14349 cfg = snd_hda_codec_get_pincfg(codec, 0x12);
14350 if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
14351 snd_hda_sequence_write(codec, verbs);
14352}
14353
Takashi Iwaiff818c22010-04-12 08:59:25 +020014354enum {
14355 ALC269_FIXUP_SONY_VAIO,
Takashi Iwai74dc8902011-01-13 14:14:41 +010014356 ALC275_FIXUP_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014357 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014358 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014359 ALC269_FIXUP_ASUS_G73JW,
Kailang Yang357f9152011-01-12 08:12:52 +010014360 ALC269_FIXUP_LENOVO_EAPD,
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014361 ALC275_FIXUP_SONY_HWEQ,
Takashi Iwai6981d182011-04-15 10:11:12 +020014362 ALC271_FIXUP_DMIC,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014363};
14364
Takashi Iwaiff818c22010-04-12 08:59:25 +020014365static const struct alc_fixup alc269_fixups[] = {
14366 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014367 .type = ALC_FIXUP_VERBS,
14368 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020014369 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14370 {}
14371 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014372 },
Takashi Iwai74dc8902011-01-13 14:14:41 +010014373 [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014374 .type = ALC_FIXUP_VERBS,
14375 .v.verbs = (const struct hda_verb[]) {
Kailang Yang27855912010-12-21 09:09:53 +010014376 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14377 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14378 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14379 { }
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014380 },
14381 .chained = true,
14382 .chain_id = ALC269_FIXUP_SONY_VAIO
Kailang Yang27855912010-12-21 09:09:53 +010014383 },
David Henningsson145a9022010-09-16 10:07:53 +020014384 [ALC269_FIXUP_DELL_M101Z] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014385 .type = ALC_FIXUP_VERBS,
14386 .v.verbs = (const struct hda_verb[]) {
David Henningsson145a9022010-09-16 10:07:53 +020014387 /* Enables internal speaker */
14388 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14389 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14390 {}
14391 }
14392 },
David Henningsson022c92b2010-12-17 20:43:04 +010014393 [ALC269_FIXUP_SKU_IGNORE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014394 .type = ALC_FIXUP_SKU,
14395 .v.sku = ALC_FIXUP_SKU_IGNORE,
David Henningssonfe67b242010-12-15 08:01:46 +010014396 },
David Henningssonac612402010-12-15 09:18:18 +010014397 [ALC269_FIXUP_ASUS_G73JW] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014398 .type = ALC_FIXUP_PINS,
14399 .v.pins = (const struct alc_pincfg[]) {
David Henningssonac612402010-12-15 09:18:18 +010014400 { 0x17, 0x99130111 }, /* subwoofer */
14401 { }
14402 }
14403 },
Kailang Yang357f9152011-01-12 08:12:52 +010014404 [ALC269_FIXUP_LENOVO_EAPD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014405 .type = ALC_FIXUP_VERBS,
14406 .v.verbs = (const struct hda_verb[]) {
Kailang Yang357f9152011-01-12 08:12:52 +010014407 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
14408 {}
14409 }
14410 },
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014411 [ALC275_FIXUP_SONY_HWEQ] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014412 .type = ALC_FIXUP_FUNC,
14413 .v.func = alc269_fixup_hweq,
14414 .chained = true,
14415 .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
Takashi Iwai6981d182011-04-15 10:11:12 +020014416 },
14417 [ALC271_FIXUP_DMIC] = {
14418 .type = ALC_FIXUP_FUNC,
14419 .v.func = alc271_fixup_dmic,
14420 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014421};
14422
Takashi Iwaia9111322011-05-02 11:30:18 +020014423static const struct snd_pci_quirk alc269_fixup_tbl[] = {
Takashi Iwai74dc8902011-01-13 14:14:41 +010014424 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
Kailang Yang1a99d4a2011-01-12 09:01:23 +010014425 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
14426 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
Takashi Iwai7039c742010-12-23 16:35:34 +010014427 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014428 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
Takashi Iwai6981d182011-04-15 10:11:12 +020014429 SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
David Henningsson022c92b2010-12-17 20:43:04 +010014430 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonded9f522011-01-26 11:46:12 +010014431 SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
14432 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
14433 SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
14434 SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014435 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Kailang Yang357f9152011-01-12 08:12:52 +010014436 SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014437 {}
14438};
14439
14440
Kailang Yangf6a92242007-12-13 16:52:54 +010014441/*
14442 * configuration and preset
14443 */
Takashi Iwaiea734962011-01-17 11:29:34 +010014444static const char * const alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014445 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014446 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014447 [ALC269_AMIC] = "laptop-amic",
14448 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014449 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014450 [ALC269_LIFEBOOK] = "lifebook",
14451 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014452};
14453
Takashi Iwaia9111322011-05-02 11:30:18 +020014454static const struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014455 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014456 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020014457 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014458 ALC269_AMIC),
14459 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14460 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14461 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14462 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14463 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14464 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14465 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14466 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14467 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
Chih-Wei Huangc790ad32011-02-25 11:14:31 +080014468 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269VB_AMIC),
Kailang Yang84898e82010-02-04 14:16:14 +010014469 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14470 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14471 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14472 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14473 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14474 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14475 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14476 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14477 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14478 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14479 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14480 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14481 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14482 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14483 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14484 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14485 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14486 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14487 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14488 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14489 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14490 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14491 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14492 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14493 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14494 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014495 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014496 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014497 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014498 ALC269_DMIC),
14499 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14500 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014501 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014502 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014503 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14504 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14505 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14506 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14507 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14508 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014509 {}
14510};
14511
Takashi Iwaia9111322011-05-02 11:30:18 +020014512static const struct alc_config_preset alc269_presets[] = {
Kailang Yangf6a92242007-12-13 16:52:54 +010014513 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014514 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014515 .init_verbs = { alc269_init_verbs },
14516 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14517 .dac_nids = alc269_dac_nids,
14518 .hp_nid = 0x03,
14519 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14520 .channel_mode = alc269_modes,
14521 .input_mux = &alc269_capture_source,
14522 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014523 [ALC269_QUANTA_FL1] = {
14524 .mixers = { alc269_quanta_fl1_mixer },
14525 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14526 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14527 .dac_nids = alc269_dac_nids,
14528 .hp_nid = 0x03,
14529 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14530 .channel_mode = alc269_modes,
14531 .input_mux = &alc269_capture_source,
14532 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014533 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014534 .init_hook = alc269_quanta_fl1_init_hook,
14535 },
Kailang Yang84898e82010-02-04 14:16:14 +010014536 [ALC269_AMIC] = {
14537 .mixers = { alc269_laptop_mixer },
14538 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014539 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014540 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014541 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14542 .dac_nids = alc269_dac_nids,
14543 .hp_nid = 0x03,
14544 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14545 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014546 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014547 .setup = alc269_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014548 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014549 },
Kailang Yang84898e82010-02-04 14:16:14 +010014550 [ALC269_DMIC] = {
14551 .mixers = { alc269_laptop_mixer },
14552 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014553 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014554 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014555 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14556 .dac_nids = alc269_dac_nids,
14557 .hp_nid = 0x03,
14558 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14559 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014560 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014561 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014562 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010014563 },
14564 [ALC269VB_AMIC] = {
14565 .mixers = { alc269vb_laptop_mixer },
14566 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14567 .init_verbs = { alc269vb_init_verbs,
14568 alc269vb_laptop_amic_init_verbs },
14569 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14570 .dac_nids = alc269_dac_nids,
14571 .hp_nid = 0x03,
14572 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14573 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014574 .unsol_event = alc_sku_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014575 .setup = alc269vb_laptop_amic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014576 .init_hook = alc_inithook,
Kailang Yang84898e82010-02-04 14:16:14 +010014577 },
14578 [ALC269VB_DMIC] = {
14579 .mixers = { alc269vb_laptop_mixer },
14580 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14581 .init_verbs = { alc269vb_init_verbs,
14582 alc269vb_laptop_dmic_init_verbs },
14583 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14584 .dac_nids = alc269_dac_nids,
14585 .hp_nid = 0x03,
14586 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14587 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014588 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014589 .setup = alc269vb_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014590 .init_hook = alc_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014591 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014592 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010014593 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010014594 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014595 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014596 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010014597 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14598 .dac_nids = alc269_dac_nids,
14599 .hp_nid = 0x03,
14600 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14601 .channel_mode = alc269_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014602 .unsol_event = alc_sku_unsol_event,
Kailang Yang84898e82010-02-04 14:16:14 +010014603 .setup = alc269_laptop_dmic_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014604 .init_hook = alc_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010014605 },
Tony Vroon64154832008-11-06 15:08:49 +000014606 [ALC269_LIFEBOOK] = {
14607 .mixers = { alc269_lifebook_mixer },
14608 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
14609 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14610 .dac_nids = alc269_dac_nids,
14611 .hp_nid = 0x03,
14612 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14613 .channel_mode = alc269_modes,
14614 .input_mux = &alc269_capture_source,
14615 .unsol_event = alc269_lifebook_unsol_event,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020014616 .setup = alc269_lifebook_setup,
Tony Vroon64154832008-11-06 15:08:49 +000014617 .init_hook = alc269_lifebook_init_hook,
14618 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014619 [ALC271_ACER] = {
14620 .mixers = { alc269_asus_mixer },
14621 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14622 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
14623 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14624 .dac_nids = alc269_dac_nids,
14625 .adc_nids = alc262_dmic_adc_nids,
14626 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
14627 .capsrc_nids = alc262_dmic_capsrc_nids,
14628 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14629 .channel_mode = alc269_modes,
14630 .input_mux = &alc269_capture_source,
14631 .dig_out_nid = ALC880_DIGOUT_NID,
14632 .unsol_event = alc_sku_unsol_event,
14633 .setup = alc269vb_laptop_dmic_setup,
14634 .init_hook = alc_inithook,
14635 },
Kailang Yangf6a92242007-12-13 16:52:54 +010014636};
14637
Kailang Yang977ddd62010-09-15 10:02:29 +020014638static int alc269_fill_coef(struct hda_codec *codec)
14639{
14640 int val;
14641
14642 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
14643 alc_write_coef_idx(codec, 0xf, 0x960b);
14644 alc_write_coef_idx(codec, 0xe, 0x8817);
14645 }
14646
14647 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
14648 alc_write_coef_idx(codec, 0xf, 0x960b);
14649 alc_write_coef_idx(codec, 0xe, 0x8814);
14650 }
14651
14652 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
14653 val = alc_read_coef_idx(codec, 0x04);
14654 /* Power up output pin */
14655 alc_write_coef_idx(codec, 0x04, val | (1<<11));
14656 }
14657
14658 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
14659 val = alc_read_coef_idx(codec, 0xd);
14660 if ((val & 0x0c00) >> 10 != 0x1) {
14661 /* Capless ramp up clock control */
Kailang Yangb896b4e2011-05-18 11:53:16 +020014662 alc_write_coef_idx(codec, 0xd, val | (1<<10));
Kailang Yang977ddd62010-09-15 10:02:29 +020014663 }
14664 val = alc_read_coef_idx(codec, 0x17);
14665 if ((val & 0x01c0) >> 6 != 0x4) {
14666 /* Class D power on reset */
Kailang Yangb896b4e2011-05-18 11:53:16 +020014667 alc_write_coef_idx(codec, 0x17, val | (1<<7));
Kailang Yang977ddd62010-09-15 10:02:29 +020014668 }
14669 }
Kailang Yangb896b4e2011-05-18 11:53:16 +020014670
14671 val = alc_read_coef_idx(codec, 0xd); /* Class D */
14672 alc_write_coef_idx(codec, 0xd, val | (1<<14));
14673
14674 val = alc_read_coef_idx(codec, 0x4); /* HP */
14675 alc_write_coef_idx(codec, 0x4, val | (1<<11));
14676
Kailang Yang977ddd62010-09-15 10:02:29 +020014677 return 0;
14678}
14679
Kailang Yangf6a92242007-12-13 16:52:54 +010014680static int patch_alc269(struct hda_codec *codec)
14681{
14682 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010014683 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010014684 int err;
14685
14686 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
14687 if (spec == NULL)
14688 return -ENOMEM;
14689
14690 codec->spec = spec;
14691
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020014692 spec->mixer_nid = 0x0b;
14693
Kailang Yangda00c242010-03-19 11:23:45 +010014694 alc_auto_parse_customize_define(codec);
14695
Kailang Yangc793bec2010-12-21 09:14:13 +010014696 if (codec->vendor_id == 0x10ec0269) {
Kailang Yangb6878572011-07-06 09:51:29 +020014697 spec->codec_variant = ALC269_TYPE_ALC269VA;
Kailang Yangc793bec2010-12-21 09:14:13 +010014698 coef = alc_read_coef_idx(codec, 0);
14699 if ((coef & 0x00f0) == 0x0010) {
14700 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
14701 spec->cdefine.platform_type == 1) {
14702 alc_codec_rename(codec, "ALC271X");
Kailang Yangc793bec2010-12-21 09:14:13 +010014703 } else if ((coef & 0xf000) == 0x2000) {
14704 alc_codec_rename(codec, "ALC259");
Kailang Yangc793bec2010-12-21 09:14:13 +010014705 } else if ((coef & 0xf000) == 0x3000) {
14706 alc_codec_rename(codec, "ALC258");
Kailang Yangb6878572011-07-06 09:51:29 +020014707 } else if ((coef & 0xfff0) == 0x3010) {
14708 alc_codec_rename(codec, "ALC277");
Kailang Yangc793bec2010-12-21 09:14:13 +010014709 } else {
14710 alc_codec_rename(codec, "ALC269VB");
Kailang Yangc793bec2010-12-21 09:14:13 +010014711 }
Kailang Yangb6878572011-07-06 09:51:29 +020014712 spec->codec_variant = ALC269_TYPE_ALC269VB;
14713 } else if ((coef & 0x00f0) == 0x0020) {
14714 if (coef == 0xa023)
14715 alc_codec_rename(codec, "ALC259");
14716 else if (coef == 0x6023)
14717 alc_codec_rename(codec, "ALC281X");
14718 else if (codec->bus->pci->subsystem_vendor == 0x17aa &&
14719 codec->bus->pci->subsystem_device == 0x21f3)
14720 alc_codec_rename(codec, "ALC3202");
14721 else
14722 alc_codec_rename(codec, "ALC269VC");
14723 spec->codec_variant = ALC269_TYPE_ALC269VC;
Kailang Yangc793bec2010-12-21 09:14:13 +010014724 } else
14725 alc_fix_pll_init(codec, 0x20, 0x04, 15);
14726 alc269_fill_coef(codec);
14727 }
Kailang Yang977ddd62010-09-15 10:02:29 +020014728
Kailang Yangf6a92242007-12-13 16:52:54 +010014729 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
14730 alc269_models,
14731 alc269_cfg_tbl);
14732
14733 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020014734 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
14735 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010014736 board_config = ALC269_AUTO;
14737 }
14738
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014739 if (board_config == ALC269_AUTO) {
14740 alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups);
14741 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
14742 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014743
Kailang Yangf6a92242007-12-13 16:52:54 +010014744 if (board_config == ALC269_AUTO) {
14745 /* automatic parse from the BIOS config */
14746 err = alc269_parse_auto_config(codec);
14747 if (err < 0) {
14748 alc_free(codec);
14749 return err;
14750 } else if (!err) {
14751 printk(KERN_INFO
14752 "hda_codec: Cannot set up configuration "
14753 "from BIOS. Using base mode...\n");
14754 board_config = ALC269_BASIC;
14755 }
14756 }
14757
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014758 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020014759 err = snd_hda_attach_beep_device(codec, 0x1);
14760 if (err < 0) {
14761 alc_free(codec);
14762 return err;
14763 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090014764 }
14765
Kailang Yangf6a92242007-12-13 16:52:54 +010014766 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020014767 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010014768
Kailang Yang84898e82010-02-04 14:16:14 +010014769 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010014770 /* Due to a hardware problem on Lenovo Ideadpad, we need to
14771 * fix the sample rate of analog I/O to 44.1kHz
14772 */
14773 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
14774 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010014775 }
Kailang Yangf6a92242007-12-13 16:52:54 +010014776
Takashi Iwai66946352010-03-29 17:21:45 +020014777 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020014778 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020014779 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020014780 alc_remove_invalid_adc_nids(codec);
Kailang Yang84898e82010-02-04 14:16:14 +010014781 }
14782
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014783 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014784 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020014785 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010014786 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010014787
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010014788 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwaiff818c22010-04-12 08:59:25 +020014789
Takashi Iwai100d5eb2009-08-10 11:55:51 +020014790 spec->vmaster_nid = 0x02;
14791
Kailang Yangf6a92242007-12-13 16:52:54 +010014792 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020014793#ifdef SND_HDA_NEEDS_RESUME
14794 codec->patch_ops.resume = alc269_resume;
14795#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010014796 if (board_config == ALC269_AUTO)
14797 spec->init_hook = alc269_auto_init;
Takashi Iwai5402e4c2011-04-07 10:39:25 +020014798 spec->shutup = alc269_shutup;
Kailang Yangbf1b0222010-10-21 08:49:56 +020014799
14800 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014801#ifdef CONFIG_SND_HDA_POWER_SAVE
14802 if (!spec->loopback.amplist)
14803 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020014804 if (alc269_mic2_for_mute_led(codec))
14805 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010014806#endif
14807
14808 return 0;
14809}
14810
14811/*
Kailang Yangdf694da2005-12-05 19:42:22 +010014812 * ALC861 channel source setting (2/6 channel selection for 3-stack)
14813 */
14814
14815/*
14816 * set the path ways for 2 channel output
14817 * need to set the codec line out and mic 1 pin widgets to inputs
14818 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014819static const struct hda_verb alc861_threestack_ch2_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014820 /* set pin widget 1Ah (line in) for input */
14821 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014822 /* set pin widget 18h (mic1/2) for input, for mic also enable
14823 * the vref
14824 */
Kailang Yangdf694da2005-12-05 19:42:22 +010014825 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14826
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014827 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14828#if 0
14829 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14830 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14831#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014832 { } /* end */
14833};
14834/*
14835 * 6ch mode
14836 * need to set the codec line out and mic 1 pin widgets to outputs
14837 */
Takashi Iwaia9111322011-05-02 11:30:18 +020014838static const struct hda_verb alc861_threestack_ch6_init[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014839 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14840 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14841 /* set pin widget 18h (mic1) for output (CLFE)*/
14842 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14843
14844 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014845 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010014846
Takashi Iwai9c7f8522006-06-28 15:08:22 +020014847 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14848#if 0
14849 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14850 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14851#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010014852 { } /* end */
14853};
14854
Takashi Iwaia9111322011-05-02 11:30:18 +020014855static const struct hda_channel_mode alc861_threestack_modes[2] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014856 { 2, alc861_threestack_ch2_init },
14857 { 6, alc861_threestack_ch6_init },
14858};
Takashi Iwai22309c32006-08-09 16:57:28 +020014859/* Set mic1 as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014860static const struct hda_verb alc861_uniwill_m31_ch2_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020014861 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14862 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14863 { } /* end */
14864};
14865/* Set mic1 as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014866static const struct hda_verb alc861_uniwill_m31_ch4_init[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020014867 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14868 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14869 { } /* end */
14870};
14871
Takashi Iwaia9111322011-05-02 11:30:18 +020014872static const struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020014873 { 2, alc861_uniwill_m31_ch2_init },
14874 { 4, alc861_uniwill_m31_ch4_init },
14875};
Kailang Yangdf694da2005-12-05 19:42:22 +010014876
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014877/* Set mic1 and line-in as input and unmute the mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014878static const struct hda_verb alc861_asus_ch2_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014879 /* set pin widget 1Ah (line in) for input */
14880 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014881 /* set pin widget 18h (mic1/2) for input, for mic also enable
14882 * the vref
14883 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014884 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
14885
14886 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
14887#if 0
14888 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
14889 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
14890#endif
14891 { } /* end */
14892};
14893/* Set mic1 nad line-in as output and mute mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020014894static const struct hda_verb alc861_asus_ch6_init[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014895 /* set pin widget 1Ah (line in) for output (Back Surround)*/
14896 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14897 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14898 /* set pin widget 18h (mic1) for output (CLFE)*/
14899 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
14900 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
14901 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
14902 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
14903
14904 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
14905#if 0
14906 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
14907 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
14908#endif
14909 { } /* end */
14910};
14911
Takashi Iwaia9111322011-05-02 11:30:18 +020014912static const struct hda_channel_mode alc861_asus_modes[2] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020014913 { 2, alc861_asus_ch2_init },
14914 { 6, alc861_asus_ch6_init },
14915};
14916
Kailang Yangdf694da2005-12-05 19:42:22 +010014917/* patch-ALC861 */
14918
Takashi Iwaia9111322011-05-02 11:30:18 +020014919static const struct snd_kcontrol_new alc861_base_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014920 /* output mixer control */
14921 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14922 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14923 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14924 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14925 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
14926
14927 /*Input mixer control */
14928 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14929 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14930 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14931 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14932 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14933 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14934 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14935 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14936 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14937 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014938
Kailang Yangdf694da2005-12-05 19:42:22 +010014939 { } /* end */
14940};
14941
Takashi Iwaia9111322011-05-02 11:30:18 +020014942static const struct snd_kcontrol_new alc861_3ST_mixer[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010014943 /* output mixer control */
14944 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14945 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14946 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14947 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14948 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14949
14950 /* Input mixer control */
14951 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14952 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14953 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14954 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14955 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14956 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14957 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14958 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14959 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
14960 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014961
Kailang Yangdf694da2005-12-05 19:42:22 +010014962 {
14963 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14964 .name = "Channel Mode",
14965 .info = alc_ch_mode_info,
14966 .get = alc_ch_mode_get,
14967 .put = alc_ch_mode_put,
14968 .private_value = ARRAY_SIZE(alc861_threestack_modes),
14969 },
14970 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014971};
14972
Takashi Iwaia9111322011-05-02 11:30:18 +020014973static const struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014974 /* output mixer control */
14975 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14976 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14977 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020014978
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014979 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020014980};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020014981
Takashi Iwaia9111322011-05-02 11:30:18 +020014982static const struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020014983 /* output mixer control */
14984 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
14985 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
14986 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
14987 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
14988 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
14989
14990 /* Input mixer control */
14991 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
14992 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
14993 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
14994 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
14995 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
14996 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
14997 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
14998 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
14999 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15000 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015001
Takashi Iwai22309c32006-08-09 16:57:28 +020015002 {
15003 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15004 .name = "Channel Mode",
15005 .info = alc_ch_mode_info,
15006 .get = alc_ch_mode_get,
15007 .put = alc_ch_mode_put,
15008 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15009 },
15010 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015011};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015012
Takashi Iwaia9111322011-05-02 11:30:18 +020015013static const struct snd_kcontrol_new alc861_asus_mixer[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015014 /* output mixer control */
15015 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15016 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15017 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15018 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15019 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15020
15021 /* Input mixer control */
15022 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15023 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15024 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15025 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15026 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15027 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15028 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15029 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15030 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015031 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15032
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015033 {
15034 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15035 .name = "Channel Mode",
15036 .info = alc_ch_mode_info,
15037 .get = alc_ch_mode_get,
15038 .put = alc_ch_mode_put,
15039 .private_value = ARRAY_SIZE(alc861_asus_modes),
15040 },
15041 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015042};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015043
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015044/* additional mixer */
Takashi Iwaia9111322011-05-02 11:30:18 +020015045static const struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015046 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15047 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015048 { }
15049};
15050
Kailang Yangdf694da2005-12-05 19:42:22 +010015051/*
15052 * generic initialization of ADC, input mixers and output mixers
15053 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015054static const struct hda_verb alc861_base_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015055 /*
15056 * Unmute ADC0 and set the default input to mic-in
15057 */
15058 /* port-A for surround (rear panel) */
15059 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15060 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15061 /* port-B for mic-in (rear panel) with vref */
15062 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15063 /* port-C for line-in (rear panel) */
15064 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15065 /* port-D for Front */
15066 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15067 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15068 /* port-E for HP out (front panel) */
15069 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15070 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015071 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015072 /* port-F for mic-in (front panel) with vref */
15073 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15074 /* port-G for CLFE (rear panel) */
15075 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15076 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15077 /* port-H for side (rear panel) */
15078 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15079 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15080 /* CD-in */
15081 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15082 /* route front mic to ADC1*/
15083 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15084 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015085
Kailang Yangdf694da2005-12-05 19:42:22 +010015086 /* Unmute DAC0~3 & spdif out*/
15087 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15088 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15089 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15090 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15091 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015092
Kailang Yangdf694da2005-12-05 19:42:22 +010015093 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15094 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15095 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15096 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15097 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015098
Kailang Yangdf694da2005-12-05 19:42:22 +010015099 /* Unmute Stereo Mixer 15 */
15100 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15101 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15102 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015103 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015104
15105 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15106 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15107 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15108 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15109 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15110 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15111 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15112 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015113 /* hp used DAC 3 (Front) */
15114 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015115 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15116
15117 { }
15118};
15119
Takashi Iwaia9111322011-05-02 11:30:18 +020015120static const struct hda_verb alc861_threestack_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015121 /*
15122 * Unmute ADC0 and set the default input to mic-in
15123 */
15124 /* port-A for surround (rear panel) */
15125 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15126 /* port-B for mic-in (rear panel) with vref */
15127 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15128 /* port-C for line-in (rear panel) */
15129 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15130 /* port-D for Front */
15131 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15132 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15133 /* port-E for HP out (front panel) */
15134 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15135 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015136 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015137 /* port-F for mic-in (front panel) with vref */
15138 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15139 /* port-G for CLFE (rear panel) */
15140 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15141 /* port-H for side (rear panel) */
15142 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15143 /* CD-in */
15144 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15145 /* route front mic to ADC1*/
15146 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15147 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15148 /* Unmute DAC0~3 & spdif out*/
15149 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15150 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15151 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15152 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15153 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015154
Kailang Yangdf694da2005-12-05 19:42:22 +010015155 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15156 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15157 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15158 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15159 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015160
Kailang Yangdf694da2005-12-05 19:42:22 +010015161 /* Unmute Stereo Mixer 15 */
15162 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15163 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15164 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015165 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015166
15167 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15168 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15169 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15170 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15171 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15172 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15173 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15174 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015175 /* hp used DAC 3 (Front) */
15176 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015177 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15178 { }
15179};
Takashi Iwai22309c32006-08-09 16:57:28 +020015180
Takashi Iwaia9111322011-05-02 11:30:18 +020015181static const struct hda_verb alc861_uniwill_m31_init_verbs[] = {
Takashi Iwai22309c32006-08-09 16:57:28 +020015182 /*
15183 * Unmute ADC0 and set the default input to mic-in
15184 */
15185 /* port-A for surround (rear panel) */
15186 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15187 /* port-B for mic-in (rear panel) with vref */
15188 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15189 /* port-C for line-in (rear panel) */
15190 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15191 /* port-D for Front */
15192 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15193 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15194 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015195 /* this has to be set to VREF80 */
15196 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015197 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015198 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015199 /* port-F for mic-in (front panel) with vref */
15200 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15201 /* port-G for CLFE (rear panel) */
15202 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15203 /* port-H for side (rear panel) */
15204 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15205 /* CD-in */
15206 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15207 /* route front mic to ADC1*/
15208 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15209 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15210 /* Unmute DAC0~3 & spdif out*/
15211 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15212 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15213 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15214 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15215 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015216
Takashi Iwai22309c32006-08-09 16:57:28 +020015217 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15218 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15219 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15220 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15221 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015222
Takashi Iwai22309c32006-08-09 16:57:28 +020015223 /* Unmute Stereo Mixer 15 */
15224 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15225 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15226 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015227 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015228
15229 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15230 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15231 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15232 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15233 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15234 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15235 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15236 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015237 /* hp used DAC 3 (Front) */
15238 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015239 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15240 { }
15241};
15242
Takashi Iwaia9111322011-05-02 11:30:18 +020015243static const struct hda_verb alc861_asus_init_verbs[] = {
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015244 /*
15245 * Unmute ADC0 and set the default input to mic-in
15246 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015247 /* port-A for surround (rear panel)
15248 * according to codec#0 this is the HP jack
15249 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015250 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15251 /* route front PCM to HP */
15252 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15253 /* port-B for mic-in (rear panel) with vref */
15254 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15255 /* port-C for line-in (rear panel) */
15256 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15257 /* port-D for Front */
15258 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15259 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15260 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015261 /* this has to be set to VREF80 */
15262 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015263 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015264 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015265 /* port-F for mic-in (front panel) with vref */
15266 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15267 /* port-G for CLFE (rear panel) */
15268 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15269 /* port-H for side (rear panel) */
15270 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15271 /* CD-in */
15272 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15273 /* route front mic to ADC1*/
15274 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15275 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15276 /* Unmute DAC0~3 & spdif out*/
15277 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15278 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15279 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15280 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15281 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15282 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15283 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15284 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15285 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15286 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015287
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015288 /* Unmute Stereo Mixer 15 */
15289 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15290 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15291 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015292 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015293
15294 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15295 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15296 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15297 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15298 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15299 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15300 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15301 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015302 /* hp used DAC 3 (Front) */
15303 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015304 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15305 { }
15306};
15307
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015308/* additional init verbs for ASUS laptops */
Takashi Iwaia9111322011-05-02 11:30:18 +020015309static const struct hda_verb alc861_asus_laptop_init_verbs[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015310 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15311 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15312 { }
15313};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015314
Takashi Iwaia9111322011-05-02 11:30:18 +020015315static const struct hda_verb alc861_toshiba_init_verbs[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015316 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015317
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015318 { }
15319};
15320
15321/* toggle speaker-output according to the hp-jack state */
15322static void alc861_toshiba_automute(struct hda_codec *codec)
15323{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015324 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015325
Takashi Iwai47fd8302007-08-10 17:11:07 +020015326 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15327 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15328 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15329 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015330}
15331
15332static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15333 unsigned int res)
15334{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015335 if ((res >> 26) == ALC880_HP_EVENT)
15336 alc861_toshiba_automute(codec);
15337}
15338
Kailang Yangdf694da2005-12-05 19:42:22 +010015339#define ALC861_DIGOUT_NID 0x07
15340
Takashi Iwaia9111322011-05-02 11:30:18 +020015341static const struct hda_channel_mode alc861_8ch_modes[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015342 { 8, NULL }
15343};
15344
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015345static const hda_nid_t alc861_dac_nids[4] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015346 /* front, surround, clfe, side */
15347 0x03, 0x06, 0x05, 0x04
15348};
15349
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015350static const hda_nid_t alc660_dac_nids[3] = {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015351 /* front, clfe, surround */
15352 0x03, 0x05, 0x06
15353};
15354
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015355static const hda_nid_t alc861_adc_nids[1] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015356 /* ADC0-2 */
15357 0x08,
15358};
15359
Takashi Iwaia9111322011-05-02 11:30:18 +020015360static const struct hda_input_mux alc861_capture_source = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015361 .num_items = 5,
15362 .items = {
15363 { "Mic", 0x0 },
15364 { "Front Mic", 0x3 },
15365 { "Line", 0x1 },
15366 { "CD", 0x4 },
15367 { "Mixer", 0x5 },
15368 },
15369};
15370
Takashi Iwai1c209302009-07-22 15:17:45 +020015371static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15372{
15373 struct alc_spec *spec = codec->spec;
15374 hda_nid_t mix, srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +020015375 int i, num;
Takashi Iwai1c209302009-07-22 15:17:45 +020015376
15377 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15378 return 0;
15379 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15380 if (num < 0)
15381 return 0;
15382 for (i = 0; i < num; i++) {
15383 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015384 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015385 if (type != AC_WID_AUD_OUT)
15386 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020015387 if (!found_in_nid_list(srcs[i], spec->multiout.dac_nids,
15388 spec->multiout.num_dacs))
Takashi Iwai1c209302009-07-22 15:17:45 +020015389 return srcs[i];
15390 }
15391 return 0;
15392}
15393
Kailang Yangdf694da2005-12-05 19:42:22 +010015394/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaicb053a82011-06-27 11:32:07 +020015395static int alc861_auto_fill_dac_nids(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015396{
Takashi Iwai1c209302009-07-22 15:17:45 +020015397 struct alc_spec *spec = codec->spec;
Takashi Iwaicb053a82011-06-27 11:32:07 +020015398 const struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010015399 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015400 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015401
15402 spec->multiout.dac_nids = spec->private_dac_nids;
15403 for (i = 0; i < cfg->line_outs; i++) {
15404 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015405 dac = alc861_look_for_dac(codec, nid);
15406 if (!dac)
15407 continue;
Takashi Iwaidda14412011-05-02 11:29:30 +020015408 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015409 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015410 return 0;
15411}
15412
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015413static int __alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15414 hda_nid_t nid, int idx, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015415{
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015416 return __add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, idx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015417 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15418}
15419
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010015420#define alc861_create_out_sw(codec, pfx, nid, chs) \
15421 __alc861_create_out_sw(codec, pfx, nid, 0, chs)
15422
Takashi Iwai1c209302009-07-22 15:17:45 +020015423/* add playback controls from the parsed DAC table */
15424static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15425 const struct auto_pin_cfg *cfg)
15426{
15427 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015428 hda_nid_t nid;
Takashi Iwaice764ab2011-04-27 16:35:23 +020015429 int i, err, noutputs;
Takashi Iwai1c209302009-07-22 15:17:45 +020015430
Takashi Iwaice764ab2011-04-27 16:35:23 +020015431 noutputs = cfg->line_outs;
15432 if (spec->multi_ios > 0)
15433 noutputs += spec->multi_ios;
15434
15435 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020015436 const char *name;
15437 int index;
Kailang Yangdf694da2005-12-05 19:42:22 +010015438 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015439 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015440 continue;
Takashi Iwai6843ca12011-06-24 11:03:58 +020015441 name = alc_get_line_out_pfx(spec, i, true, &index);
15442 if (!name) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015443 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015444 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015445 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015446 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015447 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015448 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015449 return err;
15450 } else {
David Henningsson5a882642011-03-23 08:35:07 +010015451 err = __alc861_create_out_sw(codec, name, nid, index, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015452 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015453 return err;
15454 }
15455 }
15456 return 0;
15457}
15458
Takashi Iwai1c209302009-07-22 15:17:45 +020015459static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015460{
Takashi Iwai1c209302009-07-22 15:17:45 +020015461 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015462 int err;
15463 hda_nid_t nid;
15464
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015465 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015466 return 0;
15467
15468 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015469 nid = alc861_look_for_dac(codec, pin);
15470 if (nid) {
15471 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15472 if (err < 0)
15473 return err;
15474 spec->multiout.hp_nid = nid;
15475 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015476 }
15477 return 0;
15478}
15479
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015480static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15481 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015482 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015483{
Takashi Iwai1c209302009-07-22 15:17:45 +020015484 hda_nid_t mix, srcs[5];
15485 int i, num;
15486
Jacek Luczak564c5be2008-05-03 18:41:23 +020015487 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15488 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015489 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015490 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015491 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15492 return;
15493 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15494 if (num < 0)
15495 return;
15496 for (i = 0; i < num; i++) {
15497 unsigned int mute;
15498 if (srcs[i] == dac || srcs[i] == 0x15)
15499 mute = AMP_IN_UNMUTE(i);
15500 else
15501 mute = AMP_IN_MUTE(i);
15502 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15503 mute);
15504 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015505}
15506
15507static void alc861_auto_init_multi_out(struct hda_codec *codec)
15508{
15509 struct alc_spec *spec = codec->spec;
15510 int i;
15511
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020015512 for (i = 0; i < spec->autocfg.line_outs + spec->multi_ios; i++) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015513 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015514 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010015515 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020015516 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015517 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015518 }
15519}
15520
15521static void alc861_auto_init_hp_out(struct hda_codec *codec)
15522{
15523 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015524
Takashi Iwai15870f02009-10-05 08:25:13 +020015525 if (spec->autocfg.hp_outs)
15526 alc861_auto_set_output_and_unmute(codec,
15527 spec->autocfg.hp_pins[0],
15528 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020015529 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020015530 if (spec->autocfg.speaker_outs)
15531 alc861_auto_set_output_and_unmute(codec,
15532 spec->autocfg.speaker_pins[0],
15533 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020015534 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015535}
15536
Kailang Yangdf694da2005-12-05 19:42:22 +010015537/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015538/* return 1 if successful, 0 if the proper config is not found,
15539 * or a negative error code
15540 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015541static int alc861_parse_auto_config(struct hda_codec *codec)
15542{
15543 struct alc_spec *spec = codec->spec;
15544 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015545 static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015546
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015547 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
15548 alc861_ignore);
15549 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015550 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015551 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015552 return 0; /* can't find valid BIOS pin config */
15553
Takashi Iwaicb053a82011-06-27 11:32:07 +020015554 err = alc861_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015555 if (err < 0)
15556 return err;
Takashi Iwaicb053a82011-06-27 11:32:07 +020015557 err = alc_auto_add_multi_channel_mode(codec, alc861_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020015558 if (err < 0)
15559 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015560 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015561 if (err < 0)
15562 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015563 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015564 if (err < 0)
15565 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020015566 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015567 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015568 return err;
15569
15570 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
15571
Takashi Iwai757899a2010-07-30 10:48:14 +020015572 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015573
Takashi Iwai603c4012008-07-30 15:01:44 +020015574 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010015575 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010015576
Takashi Iwai21268962011-07-07 15:01:13 +020015577 alc_remove_invalid_adc_nids(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015578
Kailang Yang6227cdc2010-02-25 08:36:52 +010015579 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai21268962011-07-07 15:01:13 +020015580 alc_auto_check_switches(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020015581
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020015582 set_capture_mixer(codec);
15583
Kailang Yangdf694da2005-12-05 19:42:22 +010015584 return 1;
15585}
15586
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015587/* additional initialization for auto-configuration model */
15588static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010015589{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015590 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015591 alc861_auto_init_multi_out(codec);
15592 alc861_auto_init_hp_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020015593 alc_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020015594 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010015595 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020015596 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010015597}
15598
Takashi Iwaicb53c622007-08-10 17:21:45 +020015599#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaia9111322011-05-02 11:30:18 +020015600static const struct hda_amp_list alc861_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +020015601 { 0x15, HDA_INPUT, 0 },
15602 { 0x15, HDA_INPUT, 1 },
15603 { 0x15, HDA_INPUT, 2 },
15604 { 0x15, HDA_INPUT, 3 },
15605 { } /* end */
15606};
15607#endif
15608
Kailang Yangdf694da2005-12-05 19:42:22 +010015609
15610/*
15611 * configuration and preset
15612 */
Takashi Iwaiea734962011-01-17 11:29:34 +010015613static const char * const alc861_models[ALC861_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015614 [ALC861_3ST] = "3stack",
15615 [ALC660_3ST] = "3stack-660",
15616 [ALC861_3ST_DIG] = "3stack-dig",
15617 [ALC861_6ST_DIG] = "6stack-dig",
15618 [ALC861_UNIWILL_M31] = "uniwill-m31",
15619 [ALC861_TOSHIBA] = "toshiba",
15620 [ALC861_ASUS] = "asus",
15621 [ALC861_ASUS_LAPTOP] = "asus-laptop",
15622 [ALC861_AUTO] = "auto",
15623};
15624
Takashi Iwaia9111322011-05-02 11:30:18 +020015625static const struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010015626 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015627 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15628 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
15629 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015630 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020015631 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010015632 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020015633 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
15634 * Any other models that need this preset?
15635 */
15636 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020015637 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
15638 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010015639 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
15640 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
15641 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
15642 /* FIXME: the below seems conflict */
15643 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
15644 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
15645 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010015646 {}
15647};
15648
Takashi Iwaia9111322011-05-02 11:30:18 +020015649static const struct alc_config_preset alc861_presets[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +010015650 [ALC861_3ST] = {
15651 .mixers = { alc861_3ST_mixer },
15652 .init_verbs = { alc861_threestack_init_verbs },
15653 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15654 .dac_nids = alc861_dac_nids,
15655 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15656 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015657 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015658 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15659 .adc_nids = alc861_adc_nids,
15660 .input_mux = &alc861_capture_source,
15661 },
15662 [ALC861_3ST_DIG] = {
15663 .mixers = { alc861_base_mixer },
15664 .init_verbs = { alc861_threestack_init_verbs },
15665 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15666 .dac_nids = alc861_dac_nids,
15667 .dig_out_nid = ALC861_DIGOUT_NID,
15668 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15669 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015670 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010015671 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15672 .adc_nids = alc861_adc_nids,
15673 .input_mux = &alc861_capture_source,
15674 },
15675 [ALC861_6ST_DIG] = {
15676 .mixers = { alc861_base_mixer },
15677 .init_verbs = { alc861_base_init_verbs },
15678 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15679 .dac_nids = alc861_dac_nids,
15680 .dig_out_nid = ALC861_DIGOUT_NID,
15681 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
15682 .channel_mode = alc861_8ch_modes,
15683 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15684 .adc_nids = alc861_adc_nids,
15685 .input_mux = &alc861_capture_source,
15686 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015687 [ALC660_3ST] = {
15688 .mixers = { alc861_3ST_mixer },
15689 .init_verbs = { alc861_threestack_init_verbs },
15690 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
15691 .dac_nids = alc660_dac_nids,
15692 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
15693 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020015694 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015695 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15696 .adc_nids = alc861_adc_nids,
15697 .input_mux = &alc861_capture_source,
15698 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015699 [ALC861_UNIWILL_M31] = {
15700 .mixers = { alc861_uniwill_m31_mixer },
15701 .init_verbs = { alc861_uniwill_m31_init_verbs },
15702 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15703 .dac_nids = alc861_dac_nids,
15704 .dig_out_nid = ALC861_DIGOUT_NID,
15705 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
15706 .channel_mode = alc861_uniwill_m31_modes,
15707 .need_dac_fix = 1,
15708 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15709 .adc_nids = alc861_adc_nids,
15710 .input_mux = &alc861_capture_source,
15711 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015712 [ALC861_TOSHIBA] = {
15713 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015714 .init_verbs = { alc861_base_init_verbs,
15715 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015716 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15717 .dac_nids = alc861_dac_nids,
15718 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15719 .channel_mode = alc883_3ST_2ch_modes,
15720 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15721 .adc_nids = alc861_adc_nids,
15722 .input_mux = &alc861_capture_source,
15723 .unsol_event = alc861_toshiba_unsol_event,
15724 .init_hook = alc861_toshiba_automute,
15725 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015726 [ALC861_ASUS] = {
15727 .mixers = { alc861_asus_mixer },
15728 .init_verbs = { alc861_asus_init_verbs },
15729 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15730 .dac_nids = alc861_dac_nids,
15731 .dig_out_nid = ALC861_DIGOUT_NID,
15732 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
15733 .channel_mode = alc861_asus_modes,
15734 .need_dac_fix = 1,
15735 .hp_nid = 0x06,
15736 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15737 .adc_nids = alc861_adc_nids,
15738 .input_mux = &alc861_capture_source,
15739 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015740 [ALC861_ASUS_LAPTOP] = {
15741 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
15742 .init_verbs = { alc861_asus_init_verbs,
15743 alc861_asus_laptop_init_verbs },
15744 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
15745 .dac_nids = alc861_dac_nids,
15746 .dig_out_nid = ALC861_DIGOUT_NID,
15747 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
15748 .channel_mode = alc883_3ST_2ch_modes,
15749 .need_dac_fix = 1,
15750 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
15751 .adc_nids = alc861_adc_nids,
15752 .input_mux = &alc861_capture_source,
15753 },
15754};
Kailang Yangdf694da2005-12-05 19:42:22 +010015755
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015756/* Pin config fixes */
15757enum {
15758 PINFIX_FSC_AMILO_PI1505,
15759};
15760
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015761static const struct alc_fixup alc861_fixups[] = {
15762 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015763 .type = ALC_FIXUP_PINS,
15764 .v.pins = (const struct alc_pincfg[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020015765 { 0x0b, 0x0221101f }, /* HP */
15766 { 0x0f, 0x90170310 }, /* speaker */
15767 { }
15768 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015769 },
15770};
15771
Takashi Iwaia9111322011-05-02 11:30:18 +020015772static const struct snd_pci_quirk alc861_fixup_tbl[] = {
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015773 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
15774 {}
15775};
Kailang Yangdf694da2005-12-05 19:42:22 +010015776
15777static int patch_alc861(struct hda_codec *codec)
15778{
15779 struct alc_spec *spec;
15780 int board_config;
15781 int err;
15782
Robert P. J. Daydc041e02006-12-19 14:44:15 +010015783 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010015784 if (spec == NULL)
15785 return -ENOMEM;
15786
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015787 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015788
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020015789 spec->mixer_nid = 0x15;
15790
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015791 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
15792 alc861_models,
15793 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015794
Takashi Iwaif5fcc132006-11-24 17:07:44 +010015795 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015796 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15797 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010015798 board_config = ALC861_AUTO;
15799 }
15800
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015801 if (board_config == ALC861_AUTO) {
15802 alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
15803 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
15804 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010015805
Kailang Yangdf694da2005-12-05 19:42:22 +010015806 if (board_config == ALC861_AUTO) {
15807 /* automatic parse from the BIOS config */
15808 err = alc861_parse_auto_config(codec);
15809 if (err < 0) {
15810 alc_free(codec);
15811 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015812 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015813 printk(KERN_INFO
15814 "hda_codec: Cannot set up configuration "
15815 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010015816 board_config = ALC861_3ST_DIG;
15817 }
15818 }
15819
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015820 err = snd_hda_attach_beep_device(codec, 0x23);
15821 if (err < 0) {
15822 alc_free(codec);
15823 return err;
15824 }
15825
Kailang Yangdf694da2005-12-05 19:42:22 +010015826 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015827 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010015828
Takashi Iwai21268962011-07-07 15:01:13 +020015829 if (!spec->adc_nids) {
15830 alc_auto_fill_adc_caps(codec);
15831 alc_rebuild_imux_for_auto_mic(codec);
15832 alc_remove_invalid_adc_nids(codec);
15833 }
15834
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010015835 if (!spec->cap_mixer)
15836 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015837 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
15838
Takashi Iwai2134ea42008-01-10 16:53:55 +010015839 spec->vmaster_nid = 0x03;
15840
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010015841 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020015842
Kailang Yangdf694da2005-12-05 19:42:22 +010015843 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050015844 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010015845 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020015846#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050015847 spec->power_hook = alc_power_eapd;
15848#endif
15849 }
15850#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020015851 if (!spec->loopback.amplist)
15852 spec->loopback.amplist = alc861_loopbacks;
15853#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020015854
Kailang Yangdf694da2005-12-05 19:42:22 +010015855 return 0;
15856}
15857
15858/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015859 * ALC861-VD support
15860 *
15861 * Based on ALC882
15862 *
15863 * In addition, an independent DAC
15864 */
15865#define ALC861VD_DIGOUT_NID 0x06
15866
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015867static const hda_nid_t alc861vd_dac_nids[4] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015868 /* front, surr, clfe, side surr */
15869 0x02, 0x03, 0x04, 0x05
15870};
15871
15872/* dac_nids for ALC660vd are in a different order - according to
15873 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015874 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015875 * of ALC660vd codecs, but for now there is only 3stack mixer
15876 * - and it is the same as in 861vd.
15877 * adc_nids in ALC660vd are (is) the same as in 861vd
15878 */
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015879static const hda_nid_t alc660vd_dac_nids[3] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015880 /* front, rear, clfe, rear_surr */
15881 0x02, 0x04, 0x03
15882};
15883
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015884static const hda_nid_t alc861vd_adc_nids[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015885 /* ADC0 */
15886 0x09,
15887};
15888
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020015889static const hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
Takashi Iwaie1406342008-02-11 18:32:32 +010015890
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015891/* input MUX */
15892/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020015893static const struct hda_input_mux alc861vd_capture_source = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015894 .num_items = 4,
15895 .items = {
15896 { "Mic", 0x0 },
15897 { "Front Mic", 0x1 },
15898 { "Line", 0x2 },
15899 { "CD", 0x4 },
15900 },
15901};
15902
Takashi Iwaia9111322011-05-02 11:30:18 +020015903static const struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010015904 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020015905 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010015906 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010015907 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020015908 },
15909};
15910
Takashi Iwaia9111322011-05-02 11:30:18 +020015911static const struct hda_input_mux alc861vd_hp_capture_source = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020015912 .num_items = 2,
15913 .items = {
15914 { "Front Mic", 0x0 },
15915 { "ATAPI Mic", 0x1 },
15916 },
15917};
15918
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015919/*
15920 * 2ch mode
15921 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015922static const struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015923 { 2, NULL }
15924};
15925
15926/*
15927 * 6ch mode
15928 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015929static const struct hda_verb alc861vd_6stack_ch6_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015930 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15931 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15932 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15933 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15934 { } /* end */
15935};
15936
15937/*
15938 * 8ch mode
15939 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015940static const struct hda_verb alc861vd_6stack_ch8_init[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015941 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15942 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15943 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15944 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
15945 { } /* end */
15946};
15947
Takashi Iwaia9111322011-05-02 11:30:18 +020015948static const struct hda_channel_mode alc861vd_6stack_modes[2] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015949 { 6, alc861vd_6stack_ch6_init },
15950 { 8, alc861vd_6stack_ch8_init },
15951};
15952
Takashi Iwaia9111322011-05-02 11:30:18 +020015953static const struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015954 {
15955 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15956 .name = "Channel Mode",
15957 .info = alc_ch_mode_info,
15958 .get = alc_ch_mode_get,
15959 .put = alc_ch_mode_put,
15960 },
15961 { } /* end */
15962};
15963
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015964/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
15965 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
15966 */
Takashi Iwaia9111322011-05-02 11:30:18 +020015967static const struct snd_kcontrol_new alc861vd_6st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015968 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
15969 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
15970
15971 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
15972 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
15973
15974 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
15975 HDA_OUTPUT),
15976 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
15977 HDA_OUTPUT),
15978 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
15979 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
15980
15981 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
15982 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
15983
15984 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
15985
David Henningsson5f99f862011-01-04 15:24:24 +010015986 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015987 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
15988 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
15989
David Henningsson5f99f862011-01-04 15:24:24 +010015990 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010015991 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
15992 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
15993
15994 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
15995 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
15996
15997 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
15998 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
15999
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016000 { } /* end */
16001};
16002
Takashi Iwaia9111322011-05-02 11:30:18 +020016003static const struct snd_kcontrol_new alc861vd_3st_mixer[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016004 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16005 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16006
16007 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16008
David Henningsson5f99f862011-01-04 15:24:24 +010016009 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016010 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16011 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16012
David Henningsson5f99f862011-01-04 15:24:24 +010016013 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016014 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16015 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16016
16017 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16018 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16019
16020 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16021 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16022
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016023 { } /* end */
16024};
16025
Takashi Iwaia9111322011-05-02 11:30:18 +020016026static const struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016027 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16028 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16029 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16030
16031 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16032
David Henningsson5f99f862011-01-04 15:24:24 +010016033 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016034 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16035 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16036
David Henningsson5f99f862011-01-04 15:24:24 +010016037 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016038 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16039 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16040
16041 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16042 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16043
16044 { } /* end */
16045};
16046
Tobin Davisb419f342008-03-07 11:57:51 +010016047/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016048 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016049 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016050static const struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016051 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16052 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016053 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16054 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016055 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016056 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16057 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016058 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016059 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16060 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016061 { } /* end */
16062};
16063
Kailang Yangd1a991a2007-08-15 16:21:59 +020016064/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16065 * Front Mic=0x18, ATAPI Mic = 0x19,
16066 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016067static const struct snd_kcontrol_new alc861vd_hp_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +020016068 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16069 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16070 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16071 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16072 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16073 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16074 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16075 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016076
Kailang Yangd1a991a2007-08-15 16:21:59 +020016077 { } /* end */
16078};
16079
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016080/*
16081 * generic initialization of ADC, input mixers and output mixers
16082 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016083static const struct hda_verb alc861vd_volume_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016084 /*
16085 * Unmute ADC0 and set the default input to mic-in
16086 */
16087 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16088 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16089
16090 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16091 * the analog-loopback mixer widget
16092 */
16093 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016094 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16095 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16096 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16097 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16098 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016099
16100 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016101 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16102 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16103 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016104 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016105
16106 /*
16107 * Set up output mixers (0x02 - 0x05)
16108 */
16109 /* set vol=0 to output mixers */
16110 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16111 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16112 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16113 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16114
16115 /* set up input amps for analog loopback */
16116 /* Amp Indices: DAC = 0, mixer = 1 */
16117 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16118 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16119 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16120 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16121 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16122 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16123 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16124 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16125
16126 { }
16127};
16128
16129/*
16130 * 3-stack pin configuration:
16131 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16132 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016133static const struct hda_verb alc861vd_3stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016134 /*
16135 * Set pin mode and muting
16136 */
16137 /* set front pin widgets 0x14 for output */
16138 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16139 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16140 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16141
16142 /* Mic (rear) pin: input vref at 80% */
16143 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16144 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16145 /* Front Mic pin: input vref at 80% */
16146 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16147 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16148 /* Line In pin: input */
16149 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16150 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16151 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16152 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16153 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16154 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16155 /* CD pin widget for input */
16156 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16157
16158 { }
16159};
16160
16161/*
16162 * 6-stack pin configuration:
16163 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016164static const struct hda_verb alc861vd_6stack_init_verbs[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016165 /*
16166 * Set pin mode and muting
16167 */
16168 /* set front pin widgets 0x14 for output */
16169 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16170 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16171 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16172
16173 /* Rear Pin: output 1 (0x0d) */
16174 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16175 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16176 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16177 /* CLFE Pin: output 2 (0x0e) */
16178 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16179 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16180 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16181 /* Side Pin: output 3 (0x0f) */
16182 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16183 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16184 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16185
16186 /* Mic (rear) pin: input vref at 80% */
16187 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16188 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16189 /* Front Mic pin: input vref at 80% */
16190 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16191 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16192 /* Line In pin: input */
16193 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16194 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16195 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16196 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16197 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16198 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16199 /* CD pin widget for input */
16200 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16201
16202 { }
16203};
16204
Takashi Iwaia9111322011-05-02 11:30:18 +020016205static const struct hda_verb alc861vd_eapd_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016206 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16207 { }
16208};
16209
Takashi Iwaia9111322011-05-02 11:30:18 +020016210static const struct hda_verb alc660vd_eapd_verbs[] = {
Kailang Yangf9423e72008-05-27 12:32:25 +020016211 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16212 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16213 { }
16214};
16215
Takashi Iwaia9111322011-05-02 11:30:18 +020016216static const struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016217 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16218 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16219 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16220 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016221 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016222 {}
16223};
16224
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016225static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016226{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016227 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016228 spec->autocfg.hp_pins[0] = 0x1b;
16229 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016230 spec->automute = 1;
16231 spec->automute_mode = ALC_AUTOMUTE_AMP;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016232}
16233
16234static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16235{
Takashi Iwaid922b512011-04-28 12:18:53 +020016236 alc_hp_automute(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016237 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016238}
16239
16240static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16241 unsigned int res)
16242{
16243 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016244 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016245 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016246 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016247 default:
Takashi Iwaid922b512011-04-28 12:18:53 +020016248 alc_sku_unsol_event(codec, res);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016249 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016250 }
16251}
16252
Takashi Iwaia9111322011-05-02 11:30:18 +020016253static const struct hda_verb alc861vd_dallas_verbs[] = {
Kailang Yang272a5272007-05-14 11:00:38 +020016254 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16255 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16256 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16257 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16258
16259 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16260 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16261 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16262 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16263 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16264 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16265 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16266 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016267
Kailang Yang272a5272007-05-14 11:00:38 +020016268 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16269 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16270 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16271 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16272 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16273 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16274 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16275 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16276
16277 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16278 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16279 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16280 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16281 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16282 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16283 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16284 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16285
16286 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16287 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16288 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16289 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16290
16291 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016292 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016293 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16294
16295 { } /* end */
16296};
16297
16298/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016299static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016300{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016301 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016302
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016303 spec->autocfg.hp_pins[0] = 0x15;
16304 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid922b512011-04-28 12:18:53 +020016305 spec->automute = 1;
16306 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang272a5272007-05-14 11:00:38 +020016307}
16308
Takashi Iwaicb53c622007-08-10 17:21:45 +020016309#ifdef CONFIG_SND_HDA_POWER_SAVE
16310#define alc861vd_loopbacks alc880_loopbacks
16311#endif
16312
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016313/*
16314 * configuration and preset
16315 */
Takashi Iwaiea734962011-01-17 11:29:34 +010016316static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016317 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016318 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016319 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016320 [ALC861VD_3ST] = "3stack",
16321 [ALC861VD_3ST_DIG] = "3stack-digout",
16322 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016323 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016324 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016325 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016326 [ALC861VD_AUTO] = "auto",
16327};
16328
Takashi Iwaia9111322011-05-02 11:30:18 +020016329static const struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016330 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16331 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016332 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016333 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016334 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016335 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016336 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016337 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016338 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016339 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016340 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016341 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016342 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016343 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016344 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016345 {}
16346};
16347
Takashi Iwaia9111322011-05-02 11:30:18 +020016348static const struct alc_config_preset alc861vd_presets[] = {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016349 [ALC660VD_3ST] = {
16350 .mixers = { alc861vd_3st_mixer },
16351 .init_verbs = { alc861vd_volume_init_verbs,
16352 alc861vd_3stack_init_verbs },
16353 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16354 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016355 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16356 .channel_mode = alc861vd_3stack_2ch_modes,
16357 .input_mux = &alc861vd_capture_source,
16358 },
Mike Crash6963f842007-06-25 12:12:51 +020016359 [ALC660VD_3ST_DIG] = {
16360 .mixers = { alc861vd_3st_mixer },
16361 .init_verbs = { alc861vd_volume_init_verbs,
16362 alc861vd_3stack_init_verbs },
16363 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16364 .dac_nids = alc660vd_dac_nids,
16365 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016366 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16367 .channel_mode = alc861vd_3stack_2ch_modes,
16368 .input_mux = &alc861vd_capture_source,
16369 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016370 [ALC861VD_3ST] = {
16371 .mixers = { alc861vd_3st_mixer },
16372 .init_verbs = { alc861vd_volume_init_verbs,
16373 alc861vd_3stack_init_verbs },
16374 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16375 .dac_nids = alc861vd_dac_nids,
16376 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16377 .channel_mode = alc861vd_3stack_2ch_modes,
16378 .input_mux = &alc861vd_capture_source,
16379 },
16380 [ALC861VD_3ST_DIG] = {
16381 .mixers = { alc861vd_3st_mixer },
16382 .init_verbs = { alc861vd_volume_init_verbs,
16383 alc861vd_3stack_init_verbs },
16384 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16385 .dac_nids = alc861vd_dac_nids,
16386 .dig_out_nid = ALC861VD_DIGOUT_NID,
16387 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16388 .channel_mode = alc861vd_3stack_2ch_modes,
16389 .input_mux = &alc861vd_capture_source,
16390 },
16391 [ALC861VD_6ST_DIG] = {
16392 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16393 .init_verbs = { alc861vd_volume_init_verbs,
16394 alc861vd_6stack_init_verbs },
16395 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16396 .dac_nids = alc861vd_dac_nids,
16397 .dig_out_nid = ALC861VD_DIGOUT_NID,
16398 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16399 .channel_mode = alc861vd_6stack_modes,
16400 .input_mux = &alc861vd_capture_source,
16401 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016402 [ALC861VD_LENOVO] = {
16403 .mixers = { alc861vd_lenovo_mixer },
16404 .init_verbs = { alc861vd_volume_init_verbs,
16405 alc861vd_3stack_init_verbs,
16406 alc861vd_eapd_verbs,
16407 alc861vd_lenovo_unsol_verbs },
16408 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16409 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016410 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16411 .channel_mode = alc861vd_3stack_2ch_modes,
16412 .input_mux = &alc861vd_capture_source,
16413 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016414 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016415 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016416 },
Kailang Yang272a5272007-05-14 11:00:38 +020016417 [ALC861VD_DALLAS] = {
16418 .mixers = { alc861vd_dallas_mixer },
16419 .init_verbs = { alc861vd_dallas_verbs },
16420 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16421 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016422 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16423 .channel_mode = alc861vd_3stack_2ch_modes,
16424 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020016425 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016426 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020016427 .init_hook = alc_hp_automute,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016428 },
16429 [ALC861VD_HP] = {
16430 .mixers = { alc861vd_hp_mixer },
16431 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16432 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16433 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016434 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016435 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16436 .channel_mode = alc861vd_3stack_2ch_modes,
16437 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaid922b512011-04-28 12:18:53 +020016438 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016439 .setup = alc861vd_dallas_setup,
Takashi Iwaid922b512011-04-28 12:18:53 +020016440 .init_hook = alc_hp_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020016441 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016442 [ALC660VD_ASUS_V1S] = {
16443 .mixers = { alc861vd_lenovo_mixer },
16444 .init_verbs = { alc861vd_volume_init_verbs,
16445 alc861vd_3stack_init_verbs,
16446 alc861vd_eapd_verbs,
16447 alc861vd_lenovo_unsol_verbs },
16448 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16449 .dac_nids = alc660vd_dac_nids,
16450 .dig_out_nid = ALC861VD_DIGOUT_NID,
16451 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16452 .channel_mode = alc861vd_3stack_2ch_modes,
16453 .input_mux = &alc861vd_capture_source,
16454 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016455 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016456 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016457 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016458};
16459
16460/*
16461 * BIOS auto configuration
16462 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016463#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
16464#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
16465
16466/* add playback controls from the parsed DAC table */
Takashi Iwai569ed342011-01-19 10:14:46 +010016467/* Based on ALC880 version. But ALC861VD has separate,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016468 * different NIDs for mute/unmute switch and volume control */
16469static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
16470 const struct auto_pin_cfg *cfg)
16471{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016472 hda_nid_t nid_v, nid_s;
Takashi Iwaice764ab2011-04-27 16:35:23 +020016473 int i, err, noutputs;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016474
Takashi Iwaice764ab2011-04-27 16:35:23 +020016475 noutputs = cfg->line_outs;
16476 if (spec->multi_ios > 0)
16477 noutputs += spec->multi_ios;
16478
16479 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020016480 const char *name;
16481 int index;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016482 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016483 continue;
16484 nid_v = alc861vd_idx_to_mixer_vol(
16485 alc880_dac_to_idx(
16486 spec->multiout.dac_nids[i]));
16487 nid_s = alc861vd_idx_to_mixer_switch(
16488 alc880_dac_to_idx(
16489 spec->multiout.dac_nids[i]));
16490
Takashi Iwai6843ca12011-06-24 11:03:58 +020016491 name = alc_get_line_out_pfx(spec, i, true, &index);
16492 if (!name) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016493 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016494 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16495 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016496 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
16497 HDA_OUTPUT));
16498 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016499 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016500 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
16501 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016502 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
16503 HDA_OUTPUT));
16504 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016505 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016506 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16507 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016508 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
16509 HDA_INPUT));
16510 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016511 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016512 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
16513 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016514 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
16515 HDA_INPUT));
16516 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016517 return err;
16518 } else {
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016519 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
David Henningsson5a882642011-03-23 08:35:07 +010016520 name, index,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016521 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
16522 HDA_OUTPUT));
16523 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016524 return err;
Takashi Iwaibcb2f0f2011-01-10 15:45:23 +010016525 err = __add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
David Henningsson5a882642011-03-23 08:35:07 +010016526 name, index,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016527 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016528 HDA_INPUT));
16529 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016530 return err;
16531 }
16532 }
16533 return 0;
16534}
16535
16536/* add playback controls for speaker and HP outputs */
16537/* Based on ALC880 version. But ALC861VD has separate,
16538 * different NIDs for mute/unmute switch and volume control */
16539static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
16540 hda_nid_t pin, const char *pfx)
16541{
16542 hda_nid_t nid_v, nid_s;
16543 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016544
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016545 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016546 return 0;
16547
16548 if (alc880_is_fixed_pin(pin)) {
16549 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
16550 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016551 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016552 spec->multiout.hp_nid = nid_v;
16553 else
16554 spec->multiout.extra_out_nid[0] = nid_v;
16555 /* control HP volume/switch on the output mixer amp */
16556 nid_v = alc861vd_idx_to_mixer_vol(
16557 alc880_fixed_pin_idx(pin));
16558 nid_s = alc861vd_idx_to_mixer_switch(
16559 alc880_fixed_pin_idx(pin));
16560
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016561 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016562 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
16563 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016564 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016565 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016566 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
16567 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016568 return err;
16569 } else if (alc880_is_multi_pin(pin)) {
16570 /* set manual connection */
16571 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020016572 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016573 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
16574 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016575 return err;
16576 }
16577 return 0;
16578}
16579
16580/* parse the BIOS configuration and set up the alc_spec
16581 * return 1 if successful, 0 if the proper config is not found,
16582 * or a negative error code
16583 * Based on ALC880 version - had to change it to override
16584 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
16585static int alc861vd_parse_auto_config(struct hda_codec *codec)
16586{
16587 struct alc_spec *spec = codec->spec;
16588 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016589 static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016590
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016591 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16592 alc861vd_ignore);
16593 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016594 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016595 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016596 return 0; /* can't find valid BIOS pin config */
16597
Takashi Iwai343a04b2011-07-06 14:28:39 +020016598 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016599 if (err < 0)
16600 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020016601 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020016602 if (err < 0)
16603 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016604 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
16605 if (err < 0)
16606 return err;
16607 err = alc861vd_auto_create_extra_out(spec,
16608 spec->autocfg.speaker_pins[0],
16609 "Speaker");
16610 if (err < 0)
16611 return err;
16612 err = alc861vd_auto_create_extra_out(spec,
16613 spec->autocfg.hp_pins[0],
16614 "Headphone");
16615 if (err < 0)
16616 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020016617 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016618 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016619 return err;
16620
16621 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16622
Takashi Iwai757899a2010-07-30 10:48:14 +020016623 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016624
Takashi Iwai603c4012008-07-30 15:01:44 +020016625 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016626 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016627
Takashi Iwai21268962011-07-07 15:01:13 +020016628 alc_remove_invalid_adc_nids(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016629
Takashi Iwai21268962011-07-07 15:01:13 +020016630 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
16631 alc_auto_check_switches(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020016632
Takashi Iwai776e1842007-08-29 15:07:11 +020016633 err = alc_auto_add_mic_boost(codec);
16634 if (err < 0)
16635 return err;
16636
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016637 return 1;
16638}
16639
16640/* additional initialization for auto-configuration model */
16641static void alc861vd_auto_init(struct hda_codec *codec)
16642{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016643 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020016644 alc_auto_init_multi_out(codec);
16645 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020016646 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020016647 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016648 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016649 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016650 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016651}
16652
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016653enum {
16654 ALC660VD_FIX_ASUS_GPIO1
16655};
16656
16657/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016658static const struct alc_fixup alc861vd_fixups[] = {
16659 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016660 .type = ALC_FIXUP_VERBS,
16661 .v.verbs = (const struct hda_verb[]) {
Takashi Iwai73413b12010-08-30 09:39:57 +020016662 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
16663 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
16664 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
16665 { }
16666 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016667 },
16668};
16669
Takashi Iwaia9111322011-05-02 11:30:18 +020016670static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016671 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
16672 {}
16673};
16674
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016675static int patch_alc861vd(struct hda_codec *codec)
16676{
16677 struct alc_spec *spec;
16678 int err, board_config;
16679
16680 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
16681 if (spec == NULL)
16682 return -ENOMEM;
16683
16684 codec->spec = spec;
16685
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020016686 spec->mixer_nid = 0x0b;
16687
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016688 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
16689 alc861vd_models,
16690 alc861vd_cfg_tbl);
16691
16692 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016693 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16694 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016695 board_config = ALC861VD_AUTO;
16696 }
16697
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016698 if (board_config == ALC861VD_AUTO) {
16699 alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
16700 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
16701 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016702
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016703 if (board_config == ALC861VD_AUTO) {
16704 /* automatic parse from the BIOS config */
16705 err = alc861vd_parse_auto_config(codec);
16706 if (err < 0) {
16707 alc_free(codec);
16708 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016709 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016710 printk(KERN_INFO
16711 "hda_codec: Cannot set up configuration "
16712 "from BIOS. Using base mode...\n");
16713 board_config = ALC861VD_3ST;
16714 }
16715 }
16716
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016717 err = snd_hda_attach_beep_device(codec, 0x23);
16718 if (err < 0) {
16719 alc_free(codec);
16720 return err;
16721 }
16722
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016723 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016724 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016725
Kailang Yang2f893282008-05-27 12:14:47 +020016726 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020016727 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010016728 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020016729 }
16730
Takashi Iwaidd704692009-08-11 08:45:11 +020016731 if (!spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020016732 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020016733 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020016734 alc_remove_invalid_adc_nids(codec);
Takashi Iwaidd704692009-08-11 08:45:11 +020016735 }
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016736
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016737 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016738 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016739
Takashi Iwai2134ea42008-01-10 16:53:55 +010016740 spec->vmaster_nid = 0x02;
16741
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010016742 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016743
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016744 codec->patch_ops = alc_patch_ops;
16745
16746 if (board_config == ALC861VD_AUTO)
16747 spec->init_hook = alc861vd_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020016748 spec->shutup = alc_eapd_shutup;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016749#ifdef CONFIG_SND_HDA_POWER_SAVE
16750 if (!spec->loopback.amplist)
16751 spec->loopback.amplist = alc861vd_loopbacks;
16752#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016753
16754 return 0;
16755}
16756
16757/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016758 * ALC662 support
16759 *
16760 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
16761 * configuration. Each pin widget can choose any input DACs and a mixer.
16762 * Each ADC is connected from a mixer of all inputs. This makes possible
16763 * 6-channel independent captures.
16764 *
16765 * In addition, an independent DAC for the multi-playback (not used in this
16766 * driver yet).
16767 */
16768#define ALC662_DIGOUT_NID 0x06
16769#define ALC662_DIGIN_NID 0x0a
16770
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016771static const hda_nid_t alc662_dac_nids[3] = {
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080016772 /* front, rear, clfe */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016773 0x02, 0x03, 0x04
16774};
16775
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016776static const hda_nid_t alc272_dac_nids[2] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020016777 0x02, 0x03
16778};
16779
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016780static const hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016781 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016782 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016783};
Takashi Iwaie1406342008-02-11 18:32:32 +010016784
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016785static const hda_nid_t alc272_adc_nids[1] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020016786 /* ADC1-2 */
16787 0x08,
16788};
16789
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020016790static const hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
16791static const hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020016792
Takashi Iwaie1406342008-02-11 18:32:32 +010016793
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016794/* input MUX */
16795/* FIXME: should be a matrix-type input source selection */
Takashi Iwaia9111322011-05-02 11:30:18 +020016796static const struct hda_input_mux alc662_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016797 .num_items = 4,
16798 .items = {
16799 { "Mic", 0x0 },
16800 { "Front Mic", 0x1 },
16801 { "Line", 0x2 },
16802 { "CD", 0x4 },
16803 },
16804};
16805
Takashi Iwaia9111322011-05-02 11:30:18 +020016806static const struct hda_input_mux alc662_lenovo_101e_capture_source = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016807 .num_items = 2,
16808 .items = {
16809 { "Mic", 0x1 },
16810 { "Line", 0x2 },
16811 },
16812};
Kailang Yang291702f2007-10-16 14:28:03 +020016813
Takashi Iwaia9111322011-05-02 11:30:18 +020016814static const struct hda_input_mux alc663_capture_source = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020016815 .num_items = 3,
16816 .items = {
16817 { "Mic", 0x0 },
16818 { "Front Mic", 0x1 },
16819 { "Line", 0x2 },
16820 },
16821};
16822
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016823#if 0 /* set to 1 for testing other input sources below */
Takashi Iwaia9111322011-05-02 11:30:18 +020016824static const struct hda_input_mux alc272_nc10_capture_source = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020016825 .num_items = 16,
16826 .items = {
16827 { "Autoselect Mic", 0x0 },
16828 { "Internal Mic", 0x1 },
16829 { "In-0x02", 0x2 },
16830 { "In-0x03", 0x3 },
16831 { "In-0x04", 0x4 },
16832 { "In-0x05", 0x5 },
16833 { "In-0x06", 0x6 },
16834 { "In-0x07", 0x7 },
16835 { "In-0x08", 0x8 },
16836 { "In-0x09", 0x9 },
16837 { "In-0x0a", 0x0a },
16838 { "In-0x0b", 0x0b },
16839 { "In-0x0c", 0x0c },
16840 { "In-0x0d", 0x0d },
16841 { "In-0x0e", 0x0e },
16842 { "In-0x0f", 0x0f },
16843 },
16844};
16845#endif
16846
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016847/*
16848 * 2ch mode
16849 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016850static const struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016851 { 2, NULL }
16852};
16853
16854/*
16855 * 2ch mode
16856 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016857static const struct hda_verb alc662_3ST_ch2_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016858 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
16859 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16860 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
16861 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
16862 { } /* end */
16863};
16864
16865/*
16866 * 6ch mode
16867 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016868static const struct hda_verb alc662_3ST_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016869 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16870 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16871 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
16872 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16873 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
16874 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
16875 { } /* end */
16876};
16877
Takashi Iwaia9111322011-05-02 11:30:18 +020016878static const struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016879 { 2, alc662_3ST_ch2_init },
16880 { 6, alc662_3ST_ch6_init },
16881};
16882
16883/*
16884 * 2ch mode
16885 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016886static const struct hda_verb alc662_sixstack_ch6_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016887 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16888 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16889 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16890 { } /* end */
16891};
16892
16893/*
16894 * 6ch mode
16895 */
Takashi Iwaia9111322011-05-02 11:30:18 +020016896static const struct hda_verb alc662_sixstack_ch8_init[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016897 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16898 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16899 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16900 { } /* end */
16901};
16902
Takashi Iwaia9111322011-05-02 11:30:18 +020016903static const struct hda_channel_mode alc662_5stack_modes[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016904 { 2, alc662_sixstack_ch6_init },
16905 { 6, alc662_sixstack_ch8_init },
16906};
16907
16908/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16909 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16910 */
16911
Takashi Iwaia9111322011-05-02 11:30:18 +020016912static const struct snd_kcontrol_new alc662_base_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016913 /* output mixer control */
16914 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016915 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016916 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016917 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016918 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16919 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016920 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16921 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016922 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16923
16924 /*Input mixer control */
16925 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
16926 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
16927 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
16928 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
16929 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
16930 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
16931 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
16932 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016933 { } /* end */
16934};
16935
Takashi Iwaia9111322011-05-02 11:30:18 +020016936static const struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016937 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016938 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016939 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16940 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16941 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16942 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16943 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16944 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16945 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16946 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16947 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016948 { } /* end */
16949};
16950
Takashi Iwaia9111322011-05-02 11:30:18 +020016951static const struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016952 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016953 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016954 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016955 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016956 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
16957 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010016958 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
16959 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016960 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16961 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16962 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16963 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16964 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16965 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16966 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16967 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16968 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016969 { } /* end */
16970};
16971
Takashi Iwaia9111322011-05-02 11:30:18 +020016972static const struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016973 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16974 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010016975 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16976 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016977 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16978 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16979 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16980 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16981 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020016982 { } /* end */
16983};
16984
Takashi Iwaia9111322011-05-02 11:30:18 +020016985static const struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020016986 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16987 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020016988
David Henningsson5f99f862011-01-04 15:24:24 +010016989 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010016990 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16991 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020016992
David Henningsson5f99f862011-01-04 15:24:24 +010016993 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010016994 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16995 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020016996 { } /* end */
16997};
16998
Takashi Iwaia9111322011-05-02 11:30:18 +020016999static const struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017000 ALC262_HIPPO_MASTER_SWITCH,
17001 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017002 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017003 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17004 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017005 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17006 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17007 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17008 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17009 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17010 { } /* end */
17011};
17012
Takashi Iwaia9111322011-05-02 11:30:18 +020017013static const struct hda_bind_ctls alc663_asus_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017014 .ops = &snd_hda_bind_vol,
17015 .values = {
17016 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17017 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17018 0
17019 },
17020};
17021
Takashi Iwaia9111322011-05-02 11:30:18 +020017022static const struct hda_bind_ctls alc663_asus_one_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017023 .ops = &snd_hda_bind_sw,
17024 .values = {
17025 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17026 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17027 0
17028 },
17029};
17030
Takashi Iwaia9111322011-05-02 11:30:18 +020017031static const struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017032 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17033 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17034 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17035 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17036 { } /* end */
17037};
17038
Takashi Iwaia9111322011-05-02 11:30:18 +020017039static const struct hda_bind_ctls alc663_asus_tree_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017040 .ops = &snd_hda_bind_sw,
17041 .values = {
17042 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17043 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17044 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17045 0
17046 },
17047};
17048
Takashi Iwaia9111322011-05-02 11:30:18 +020017049static const struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017050 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17051 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17052 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17053 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17054 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17055 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17056
17057 { } /* end */
17058};
17059
Takashi Iwaia9111322011-05-02 11:30:18 +020017060static const struct hda_bind_ctls alc663_asus_four_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017061 .ops = &snd_hda_bind_sw,
17062 .values = {
17063 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17064 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17065 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17066 0
17067 },
17068};
17069
Takashi Iwaia9111322011-05-02 11:30:18 +020017070static const struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017071 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17072 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17073 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17074 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17075 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17076 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17077 { } /* end */
17078};
17079
Takashi Iwaia9111322011-05-02 11:30:18 +020017080static const struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017081 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17082 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017083 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17084 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17085 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17086 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17087 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17088 { } /* end */
17089};
17090
Takashi Iwaia9111322011-05-02 11:30:18 +020017091static const struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017092 .ops = &snd_hda_bind_vol,
17093 .values = {
17094 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17095 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17096 0
17097 },
17098};
17099
Takashi Iwaia9111322011-05-02 11:30:18 +020017100static const struct hda_bind_ctls alc663_asus_two_bind_switch = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017101 .ops = &snd_hda_bind_sw,
17102 .values = {
17103 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17104 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17105 0
17106 },
17107};
17108
Takashi Iwaia9111322011-05-02 11:30:18 +020017109static const struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017110 HDA_BIND_VOL("Master Playback Volume",
17111 &alc663_asus_two_bind_master_vol),
17112 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17113 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017114 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17115 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17116 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017117 { } /* end */
17118};
17119
Takashi Iwaia9111322011-05-02 11:30:18 +020017120static const struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017121 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17122 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17123 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17124 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17125 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17126 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017127 { } /* end */
17128};
17129
Takashi Iwaia9111322011-05-02 11:30:18 +020017130static const struct snd_kcontrol_new alc663_g71v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017131 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17132 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17133 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17134 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17135 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17136
17137 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17138 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017139 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17140 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017141 { } /* end */
17142};
17143
Takashi Iwaia9111322011-05-02 11:30:18 +020017144static const struct snd_kcontrol_new alc663_g50v_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017145 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17146 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17147 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17148
17149 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17150 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017151 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17152 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017153 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17154 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17155 { } /* end */
17156};
17157
Takashi Iwaia9111322011-05-02 11:30:18 +020017158static const struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017159 .ops = &snd_hda_bind_sw,
17160 .values = {
17161 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17162 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17163 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17164 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17165 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17166 0
17167 },
17168};
17169
Takashi Iwaia9111322011-05-02 11:30:18 +020017170static const struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017171 .ops = &snd_hda_bind_sw,
17172 .values = {
17173 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17174 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17175 0
17176 },
17177};
17178
Takashi Iwaia9111322011-05-02 11:30:18 +020017179static const struct snd_kcontrol_new alc663_mode7_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017180 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17181 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17182 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17183 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17184 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17185 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17186 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17187 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17188 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17189 { } /* end */
17190};
17191
Takashi Iwaia9111322011-05-02 11:30:18 +020017192static const struct snd_kcontrol_new alc663_mode8_mixer[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017193 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17194 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17195 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17196 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17197 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17198 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17199 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17200 { } /* end */
17201};
17202
17203
Takashi Iwaia9111322011-05-02 11:30:18 +020017204static const struct snd_kcontrol_new alc662_chmode_mixer[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017205 {
17206 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17207 .name = "Channel Mode",
17208 .info = alc_ch_mode_info,
17209 .get = alc_ch_mode_get,
17210 .put = alc_ch_mode_put,
17211 },
17212 { } /* end */
17213};
17214
Takashi Iwaia9111322011-05-02 11:30:18 +020017215static const struct hda_verb alc662_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017216 /* ADC: mute amp left and right */
17217 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17218 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017219
Kailang Yangb60dd392007-09-20 12:50:29 +020017220 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17221 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17222 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17223 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17224 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17225 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017226
17227 /* Front Pin: output 0 (0x0c) */
17228 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17229 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17230
17231 /* Rear Pin: output 1 (0x0d) */
17232 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17233 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17234
17235 /* CLFE Pin: output 2 (0x0e) */
17236 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17237 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17238
17239 /* Mic (rear) pin: input vref at 80% */
17240 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17241 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17242 /* Front Mic pin: input vref at 80% */
17243 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17244 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17245 /* Line In pin: input */
17246 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17247 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17248 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17249 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17250 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17251 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17252 /* CD pin widget for input */
17253 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17254
17255 /* FIXME: use matrix-type input source selection */
17256 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17257 /* Input mixer */
17258 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017259 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017260
Takashi Iwaia7f23712011-04-07 10:24:23 +020017261 { }
17262};
17263
Takashi Iwaia9111322011-05-02 11:30:18 +020017264static const struct hda_verb alc662_eapd_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017265 /* always trun on EAPD */
17266 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17267 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017268 { }
17269};
17270
Takashi Iwaia9111322011-05-02 11:30:18 +020017271static const struct hda_verb alc662_sue_init_verbs[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017272 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17273 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017274 {}
17275};
17276
Takashi Iwaia9111322011-05-02 11:30:18 +020017277static const struct hda_verb alc662_eeepc_sue_init_verbs[] = {
Kailang Yang291702f2007-10-16 14:28:03 +020017278 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17279 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17280 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017281};
17282
Kailang Yang8c427222008-01-10 13:03:59 +010017283/* Set Unsolicited Event*/
Takashi Iwaia9111322011-05-02 11:30:18 +020017284static const struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
Kailang Yang8c427222008-01-10 13:03:59 +010017285 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17286 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17287 {}
17288};
17289
Takashi Iwaia9111322011-05-02 11:30:18 +020017290static const struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017291 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17292 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017293 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17294 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017295 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17296 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17297 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017298 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17299 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17300 {}
17301};
17302
Takashi Iwaia9111322011-05-02 11:30:18 +020017303static const struct hda_verb alc663_21jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017304 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17305 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17306 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17307 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17308 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17309 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17310 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17311 {}
17312};
17313
Takashi Iwaia9111322011-05-02 11:30:18 +020017314static const struct hda_verb alc662_1bjd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017315 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17316 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17317 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17318 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17319 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17320 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17321 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17322 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17323 {}
17324};
17325
Takashi Iwaia9111322011-05-02 11:30:18 +020017326static const struct hda_verb alc663_15jd_amic_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017327 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17328 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17329 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17330 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17331 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17332 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17333 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17334 {}
17335};
17336
Takashi Iwaia9111322011-05-02 11:30:18 +020017337static const struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017338 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17339 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17340 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17341 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17342 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17343 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17344 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17345 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17346 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17347 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17348 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17349 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17350 {}
17351};
17352
Takashi Iwaia9111322011-05-02 11:30:18 +020017353static const struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017354 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17355 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17356 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17357 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17358 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17359 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17360 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17361 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17362 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17363 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17364 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17365 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17366 {}
17367};
17368
Takashi Iwaia9111322011-05-02 11:30:18 +020017369static const struct hda_verb alc663_g71v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017370 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17371 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17372 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17373
17374 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17375 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17376 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17377
17378 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17379 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17380 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17381 {}
17382};
17383
Takashi Iwaia9111322011-05-02 11:30:18 +020017384static const struct hda_verb alc663_g50v_init_verbs[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017385 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17386 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17387 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17388
17389 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17390 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17391 {}
17392};
17393
Takashi Iwaia9111322011-05-02 11:30:18 +020017394static const struct hda_verb alc662_ecs_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017395 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17396 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17397 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17398 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17399 {}
17400};
17401
Takashi Iwaia9111322011-05-02 11:30:18 +020017402static const struct hda_verb alc272_dell_zm1_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017403 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17404 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17405 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17406 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17407 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17408 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17409 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17410 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17411 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17412 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17413 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17414 {}
17415};
17416
Takashi Iwaia9111322011-05-02 11:30:18 +020017417static const struct hda_verb alc272_dell_init_verbs[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017418 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17419 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17420 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17421 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17422 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17423 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17424 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17425 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17426 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17427 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17428 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17429 {}
17430};
17431
Takashi Iwaia9111322011-05-02 11:30:18 +020017432static const struct hda_verb alc663_mode7_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017433 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17434 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17435 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17436 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17437 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17438 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17439 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
17440 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17441 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17442 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17443 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17444 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17445 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17446 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17447 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17448 {}
17449};
17450
Takashi Iwaia9111322011-05-02 11:30:18 +020017451static const struct hda_verb alc663_mode8_init_verbs[] = {
Kailang Yangebb83ee2009-12-17 12:23:00 +010017452 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17453 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17454 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17455 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
17456 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17457 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17458 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17459 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17460 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17461 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17462 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17463 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17464 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17465 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17466 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17467 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17468 {}
17469};
17470
Takashi Iwaia9111322011-05-02 11:30:18 +020017471static const struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017472 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
17473 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
17474 { } /* end */
17475};
17476
Takashi Iwaia9111322011-05-02 11:30:18 +020017477static const struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
Kailang Yang622e84c2009-04-21 07:39:04 +020017478 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
17479 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
17480 { } /* end */
17481};
17482
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017483static void alc662_lenovo_101e_setup(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017484{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017485 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017486
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017487 spec->autocfg.hp_pins[0] = 0x1b;
17488 spec->autocfg.line_out_pins[0] = 0x14;
17489 spec->autocfg.speaker_pins[0] = 0x15;
17490 spec->automute = 1;
17491 spec->detect_line = 1;
17492 spec->automute_lines = 1;
17493 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017494}
17495
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017496static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020017497{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017498 struct alc_spec *spec = codec->spec;
17499
17500 alc262_hippo1_setup(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020017501 spec->ext_mic_pin = 0x18;
17502 spec->int_mic_pin = 0x19;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017503 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020017504}
17505
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017506static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010017507{
Takashi Iwai42171c12009-05-08 14:11:43 +020017508 struct alc_spec *spec = codec->spec;
17509
17510 spec->autocfg.hp_pins[0] = 0x14;
17511 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaie9427962011-04-28 15:46:07 +020017512 spec->automute = 1;
17513 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yang8c427222008-01-10 13:03:59 +010017514}
17515
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017516static void alc663_m51va_setup(struct hda_codec *codec)
17517{
17518 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017519 spec->autocfg.hp_pins[0] = 0x21;
17520 spec->autocfg.speaker_pins[0] = 0x14;
17521 spec->automute_mixer_nid[0] = 0x0c;
17522 spec->automute = 1;
17523 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020017524 spec->ext_mic_pin = 0x18;
17525 spec->int_mic_pin = 0x12;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017526 spec->auto_mic = 1;
17527}
17528
Kailang Yangf1d4e282008-08-26 14:03:29 +020017529/* ***************** Mode1 ******************************/
Kailang Yangebb83ee2009-12-17 12:23:00 +010017530static void alc663_mode1_setup(struct hda_codec *codec)
17531{
17532 struct alc_spec *spec = codec->spec;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017533 spec->autocfg.hp_pins[0] = 0x21;
17534 spec->autocfg.speaker_pins[0] = 0x14;
17535 spec->automute_mixer_nid[0] = 0x0c;
17536 spec->automute = 1;
17537 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020017538 spec->ext_mic_pin = 0x18;
17539 spec->int_mic_pin = 0x19;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017540 spec->auto_mic = 1;
17541}
17542
Kailang Yangf1d4e282008-08-26 14:03:29 +020017543/* ***************** Mode2 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017544static void alc662_mode2_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017545{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017546 struct alc_spec *spec = codec->spec;
17547 spec->autocfg.hp_pins[0] = 0x1b;
17548 spec->autocfg.speaker_pins[0] = 0x14;
17549 spec->automute = 1;
17550 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai21268962011-07-07 15:01:13 +020017551 spec->ext_mic_pin = 0x18;
17552 spec->int_mic_pin = 0x19;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017553 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017554}
17555
Kailang Yangf1d4e282008-08-26 14:03:29 +020017556/* ***************** Mode3 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017557static void alc663_mode3_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017558{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017559 struct alc_spec *spec = codec->spec;
17560 spec->autocfg.hp_pins[0] = 0x21;
17561 spec->autocfg.hp_pins[0] = 0x15;
17562 spec->autocfg.speaker_pins[0] = 0x14;
17563 spec->automute = 1;
17564 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai21268962011-07-07 15:01:13 +020017565 spec->ext_mic_pin = 0x18;
17566 spec->int_mic_pin = 0x19;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017567 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017568}
17569
Kailang Yangf1d4e282008-08-26 14:03:29 +020017570/* ***************** Mode4 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017571static void alc663_mode4_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017572{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017573 struct alc_spec *spec = codec->spec;
17574 spec->autocfg.hp_pins[0] = 0x21;
17575 spec->autocfg.speaker_pins[0] = 0x14;
17576 spec->autocfg.speaker_pins[1] = 0x16;
17577 spec->automute_mixer_nid[0] = 0x0c;
17578 spec->automute_mixer_nid[1] = 0x0e;
17579 spec->automute = 1;
17580 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020017581 spec->ext_mic_pin = 0x18;
17582 spec->int_mic_pin = 0x19;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017583 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017584}
17585
Kailang Yangf1d4e282008-08-26 14:03:29 +020017586/* ***************** Mode5 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017587static void alc663_mode5_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017588{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017589 struct alc_spec *spec = codec->spec;
17590 spec->autocfg.hp_pins[0] = 0x15;
17591 spec->autocfg.speaker_pins[0] = 0x14;
17592 spec->autocfg.speaker_pins[1] = 0x16;
17593 spec->automute_mixer_nid[0] = 0x0c;
17594 spec->automute_mixer_nid[1] = 0x0e;
17595 spec->automute = 1;
17596 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020017597 spec->ext_mic_pin = 0x18;
17598 spec->int_mic_pin = 0x19;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017599 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017600}
17601
Kailang Yangf1d4e282008-08-26 14:03:29 +020017602/* ***************** Mode6 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017603static void alc663_mode6_setup(struct hda_codec *codec)
Kailang Yangf1d4e282008-08-26 14:03:29 +020017604{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017605 struct alc_spec *spec = codec->spec;
17606 spec->autocfg.hp_pins[0] = 0x1b;
17607 spec->autocfg.hp_pins[0] = 0x15;
17608 spec->autocfg.speaker_pins[0] = 0x14;
17609 spec->automute_mixer_nid[0] = 0x0c;
17610 spec->automute = 1;
17611 spec->automute_mode = ALC_AUTOMUTE_MIXER;
Takashi Iwai21268962011-07-07 15:01:13 +020017612 spec->ext_mic_pin = 0x18;
17613 spec->int_mic_pin = 0x19;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017614 spec->auto_mic = 1;
Kailang Yangf1d4e282008-08-26 14:03:29 +020017615}
17616
Kailang Yangebb83ee2009-12-17 12:23:00 +010017617/* ***************** Mode7 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017618static void alc663_mode7_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010017619{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017620 struct alc_spec *spec = codec->spec;
17621 spec->autocfg.hp_pins[0] = 0x1b;
17622 spec->autocfg.hp_pins[0] = 0x21;
17623 spec->autocfg.speaker_pins[0] = 0x14;
17624 spec->autocfg.speaker_pins[0] = 0x17;
17625 spec->automute = 1;
17626 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai21268962011-07-07 15:01:13 +020017627 spec->ext_mic_pin = 0x18;
17628 spec->int_mic_pin = 0x19;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017629 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017630}
17631
17632/* ***************** Mode8 ******************************/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017633static void alc663_mode8_setup(struct hda_codec *codec)
Kailang Yangebb83ee2009-12-17 12:23:00 +010017634{
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017635 struct alc_spec *spec = codec->spec;
17636 spec->autocfg.hp_pins[0] = 0x21;
17637 spec->autocfg.hp_pins[1] = 0x15;
17638 spec->autocfg.speaker_pins[0] = 0x14;
17639 spec->autocfg.speaker_pins[0] = 0x17;
17640 spec->automute = 1;
17641 spec->automute_mode = ALC_AUTOMUTE_PIN;
Takashi Iwai21268962011-07-07 15:01:13 +020017642 spec->ext_mic_pin = 0x18;
17643 spec->int_mic_pin = 0x12;
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017644 spec->auto_mic = 1;
Kailang Yangebb83ee2009-12-17 12:23:00 +010017645}
17646
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017647static void alc663_g71v_setup(struct hda_codec *codec)
Kailang Yang6dda9f42008-05-27 12:05:31 +020017648{
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017649 struct alc_spec *spec = codec->spec;
17650 spec->autocfg.hp_pins[0] = 0x21;
17651 spec->autocfg.line_out_pins[0] = 0x15;
17652 spec->autocfg.speaker_pins[0] = 0x14;
17653 spec->automute = 1;
17654 spec->automute_mode = ALC_AUTOMUTE_AMP;
17655 spec->detect_line = 1;
17656 spec->automute_lines = 1;
Takashi Iwai21268962011-07-07 15:01:13 +020017657 spec->ext_mic_pin = 0x18;
17658 spec->int_mic_pin = 0x12;
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017659 spec->auto_mic = 1;
Kailang Yang6dda9f42008-05-27 12:05:31 +020017660}
17661
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017662#define alc663_g50v_setup alc663_m51va_setup
17663
Takashi Iwaia9111322011-05-02 11:30:18 +020017664static const struct snd_kcontrol_new alc662_ecs_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017665 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020017666 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017667
David Henningsson5f99f862011-01-04 15:24:24 +010017668 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017669 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
17670 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017671
David Henningsson5f99f862011-01-04 15:24:24 +010017672 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017673 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17674 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017675 { } /* end */
17676};
17677
Takashi Iwaia9111322011-05-02 11:30:18 +020017678static const struct snd_kcontrol_new alc272_nc10_mixer[] = {
Chris Pockelé9541ba12009-05-12 08:08:53 +020017679 /* Master Playback automatically created from Speaker and Headphone */
17680 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17681 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17682 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17683 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17684
David Henningsson8607f7c2010-12-20 14:43:54 +010017685 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17686 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010017687 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017688
David Henningsson28c4edb2010-12-20 14:24:29 +010017689 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17690 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010017691 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017692 { } /* end */
17693};
17694
Takashi Iwaicb53c622007-08-10 17:21:45 +020017695#ifdef CONFIG_SND_HDA_POWER_SAVE
17696#define alc662_loopbacks alc880_loopbacks
17697#endif
17698
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017699
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017700/*
17701 * configuration and preset
17702 */
Takashi Iwaiea734962011-01-17 11:29:34 +010017703static const char * const alc662_models[ALC662_MODEL_LAST] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017704 [ALC662_3ST_2ch_DIG] = "3stack-dig",
17705 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
17706 [ALC662_3ST_6ch] = "3stack-6ch",
Raymond Yau4bf4a6c2011-04-05 22:47:15 +080017707 [ALC662_5ST_DIG] = "5stack-dig",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017708 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020017709 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010017710 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017711 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020017712 [ALC663_ASUS_M51VA] = "m51va",
17713 [ALC663_ASUS_G71V] = "g71v",
17714 [ALC663_ASUS_H13] = "h13",
17715 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020017716 [ALC663_ASUS_MODE1] = "asus-mode1",
17717 [ALC662_ASUS_MODE2] = "asus-mode2",
17718 [ALC663_ASUS_MODE3] = "asus-mode3",
17719 [ALC663_ASUS_MODE4] = "asus-mode4",
17720 [ALC663_ASUS_MODE5] = "asus-mode5",
17721 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010017722 [ALC663_ASUS_MODE7] = "asus-mode7",
17723 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020017724 [ALC272_DELL] = "dell",
17725 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020017726 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017727 [ALC662_AUTO] = "auto",
17728};
17729
Takashi Iwaia9111322011-05-02 11:30:18 +020017730static const struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010017731 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020017732 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
17733 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017734 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
17735 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010017736 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017737 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
17738 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
17739 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
17740 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017741 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
17742 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017743 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017744 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
17745 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
17746 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
17747 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
17748 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017749 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017750 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
17751 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017752 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
17753 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
17754 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
17755 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010017756 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020017757 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
17758 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
17759 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017760 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
17761 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
17762 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
17763 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017764 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017765 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
17766 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017767 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017768 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
17769 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
17770 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017771 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010017772 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020017773 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
17774 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017775 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
17776 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
17777 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017778 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017779 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
17780 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020017781 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017782 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020017783 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017784 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
17785 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
17786 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020017787 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017788 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
17789 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010017790 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020017791 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010017792 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017793 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030017794 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
17795 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010017796 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020017797 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Takashi Iwaiebb47242011-05-02 10:37:29 +020017798 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
17799 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010017800 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020017801 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020017802 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017803 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020017804 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020017805 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010017806 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
17807 ALC663_ASUS_H13),
Anisse Astier965b76d2011-02-10 13:14:44 +010017808 SND_PCI_QUIRK(0x1991, 0x5628, "Ordissimo EVE", ALC662_LENOVO_101E),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017809 {}
17810};
17811
Takashi Iwaia9111322011-05-02 11:30:18 +020017812static const struct alc_config_preset alc662_presets[] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017813 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017814 .mixers = { alc662_3ST_2ch_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017815 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017816 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17817 .dac_nids = alc662_dac_nids,
17818 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017819 .dig_in_nid = ALC662_DIGIN_NID,
17820 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17821 .channel_mode = alc662_3ST_2ch_modes,
17822 .input_mux = &alc662_capture_source,
17823 },
17824 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017825 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017826 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017827 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17828 .dac_nids = alc662_dac_nids,
17829 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017830 .dig_in_nid = ALC662_DIGIN_NID,
17831 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17832 .channel_mode = alc662_3ST_6ch_modes,
17833 .need_dac_fix = 1,
17834 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017835 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017836 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017837 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017838 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017839 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17840 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017841 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17842 .channel_mode = alc662_3ST_6ch_modes,
17843 .need_dac_fix = 1,
17844 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017845 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017846 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017847 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017848 .init_verbs = { alc662_init_verbs, alc662_eapd_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017849 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17850 .dac_nids = alc662_dac_nids,
17851 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017852 .dig_in_nid = ALC662_DIGIN_NID,
17853 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
17854 .channel_mode = alc662_5stack_modes,
17855 .input_mux = &alc662_capture_source,
17856 },
17857 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017858 .mixers = { alc662_lenovo_101e_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017859 .init_verbs = { alc662_init_verbs,
17860 alc662_eapd_init_verbs,
17861 alc662_sue_init_verbs },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017862 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17863 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017864 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17865 .channel_mode = alc662_3ST_2ch_modes,
17866 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017867 .unsol_event = alc_sku_unsol_event,
17868 .setup = alc662_lenovo_101e_setup,
17869 .init_hook = alc_inithook,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017870 },
Kailang Yang291702f2007-10-16 14:28:03 +020017871 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017872 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020017873 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017874 alc662_eapd_init_verbs,
Kailang Yang291702f2007-10-16 14:28:03 +020017875 alc662_eeepc_sue_init_verbs },
17876 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17877 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020017878 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17879 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020017880 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017881 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020017882 .init_hook = alc_inithook,
Kailang Yang291702f2007-10-16 14:28:03 +020017883 },
Kailang Yang8c427222008-01-10 13:03:59 +010017884 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017885 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010017886 alc662_chmode_mixer },
17887 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017888 alc662_eapd_init_verbs,
Kailang Yang8c427222008-01-10 13:03:59 +010017889 alc662_eeepc_ep20_sue_init_verbs },
17890 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17891 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010017892 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17893 .channel_mode = alc662_3ST_6ch_modes,
17894 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwaie9427962011-04-28 15:46:07 +020017895 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017896 .setup = alc662_eeepc_ep20_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020017897 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010017898 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017899 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017900 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017901 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017902 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017903 alc662_ecs_init_verbs },
17904 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17905 .dac_nids = alc662_dac_nids,
17906 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17907 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie9427962011-04-28 15:46:07 +020017908 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017909 .setup = alc662_eeepc_setup,
Takashi Iwaie9427962011-04-28 15:46:07 +020017910 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017911 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017912 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017913 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017914 .init_verbs = { alc662_init_verbs,
17915 alc662_eapd_init_verbs,
17916 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017917 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17918 .dac_nids = alc662_dac_nids,
17919 .dig_out_nid = ALC662_DIGOUT_NID,
17920 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17921 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017922 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017923 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017924 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017925 },
17926 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017927 .mixers = { alc663_g71v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017928 .init_verbs = { alc662_init_verbs,
17929 alc662_eapd_init_verbs,
17930 alc663_g71v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017931 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17932 .dac_nids = alc662_dac_nids,
17933 .dig_out_nid = ALC662_DIGOUT_NID,
17934 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17935 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017936 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017937 .setup = alc663_g71v_setup,
Takashi Iwaie6a5e1b2011-04-28 14:41:52 +020017938 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017939 },
17940 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017941 .mixers = { alc663_m51va_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017942 .init_verbs = { alc662_init_verbs,
17943 alc662_eapd_init_verbs,
17944 alc663_m51va_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017945 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17946 .dac_nids = alc662_dac_nids,
17947 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17948 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017949 .setup = alc663_m51va_setup,
17950 .unsol_event = alc_sku_unsol_event,
17951 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017952 },
17953 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017954 .mixers = { alc663_g50v_mixer },
Takashi Iwaia7f23712011-04-07 10:24:23 +020017955 .init_verbs = { alc662_init_verbs,
17956 alc662_eapd_init_verbs,
17957 alc663_g50v_init_verbs },
Kailang Yang6dda9f42008-05-27 12:05:31 +020017958 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17959 .dac_nids = alc662_dac_nids,
17960 .dig_out_nid = ALC662_DIGOUT_NID,
17961 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
17962 .channel_mode = alc662_3ST_6ch_modes,
17963 .input_mux = &alc663_capture_source,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017964 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017965 .setup = alc663_g50v_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017966 .init_hook = alc_inithook,
Kailang Yang6dda9f42008-05-27 12:05:31 +020017967 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020017968 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017969 .mixers = { alc663_m51va_mixer },
17970 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017971 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017972 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017973 alc663_21jd_amic_init_verbs },
17974 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17975 .hp_nid = 0x03,
17976 .dac_nids = alc662_dac_nids,
17977 .dig_out_nid = ALC662_DIGOUT_NID,
17978 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17979 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017980 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017981 .setup = alc663_mode1_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017982 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017983 },
17984 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010017985 .mixers = { alc662_1bjd_mixer },
17986 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017987 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020017988 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017989 alc662_1bjd_amic_init_verbs },
17990 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
17991 .dac_nids = alc662_dac_nids,
17992 .dig_out_nid = ALC662_DIGOUT_NID,
17993 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
17994 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017995 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017996 .setup = alc662_mode2_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020017997 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020017998 },
17999 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018000 .mixers = { alc663_two_hp_m1_mixer },
18001 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018002 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018003 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018004 alc663_two_hp_amic_m1_init_verbs },
18005 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18006 .hp_nid = 0x03,
18007 .dac_nids = alc662_dac_nids,
18008 .dig_out_nid = ALC662_DIGOUT_NID,
18009 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18010 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018011 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018012 .setup = alc663_mode3_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018013 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018014 },
18015 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018016 .mixers = { alc663_asus_21jd_clfe_mixer },
18017 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018018 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018019 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018020 alc663_21jd_amic_init_verbs},
18021 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18022 .hp_nid = 0x03,
18023 .dac_nids = alc662_dac_nids,
18024 .dig_out_nid = ALC662_DIGOUT_NID,
18025 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18026 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018027 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018028 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018029 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018030 },
18031 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018032 .mixers = { alc663_asus_15jd_clfe_mixer },
18033 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018034 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018035 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018036 alc663_15jd_amic_init_verbs },
18037 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18038 .hp_nid = 0x03,
18039 .dac_nids = alc662_dac_nids,
18040 .dig_out_nid = ALC662_DIGOUT_NID,
18041 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18042 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018043 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018044 .setup = alc663_mode5_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018045 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018046 },
18047 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018048 .mixers = { alc663_two_hp_m2_mixer },
18049 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018050 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018051 alc662_eapd_init_verbs,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018052 alc663_two_hp_amic_m2_init_verbs },
18053 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18054 .hp_nid = 0x03,
18055 .dac_nids = alc662_dac_nids,
18056 .dig_out_nid = ALC662_DIGOUT_NID,
18057 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18058 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018059 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018060 .setup = alc663_mode6_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018061 .init_hook = alc_inithook,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018062 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018063 [ALC663_ASUS_MODE7] = {
18064 .mixers = { alc663_mode7_mixer },
18065 .cap_mixer = alc662_auto_capture_mixer,
18066 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018067 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018068 alc663_mode7_init_verbs },
18069 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18070 .hp_nid = 0x03,
18071 .dac_nids = alc662_dac_nids,
18072 .dig_out_nid = ALC662_DIGOUT_NID,
18073 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18074 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018075 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018076 .setup = alc663_mode7_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018077 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018078 },
18079 [ALC663_ASUS_MODE8] = {
18080 .mixers = { alc663_mode8_mixer },
18081 .cap_mixer = alc662_auto_capture_mixer,
18082 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018083 alc662_eapd_init_verbs,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018084 alc663_mode8_init_verbs },
18085 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18086 .hp_nid = 0x03,
18087 .dac_nids = alc662_dac_nids,
18088 .dig_out_nid = ALC662_DIGOUT_NID,
18089 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18090 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018091 .unsol_event = alc_sku_unsol_event,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018092 .setup = alc663_mode8_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018093 .init_hook = alc_inithook,
Kailang Yangebb83ee2009-12-17 12:23:00 +010018094 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018095 [ALC272_DELL] = {
18096 .mixers = { alc663_m51va_mixer },
18097 .cap_mixer = alc272_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018098 .init_verbs = { alc662_init_verbs,
18099 alc662_eapd_init_verbs,
18100 alc272_dell_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018101 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018102 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018103 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18104 .adc_nids = alc272_adc_nids,
18105 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18106 .capsrc_nids = alc272_capsrc_nids,
18107 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018108 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018109 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018110 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018111 },
18112 [ALC272_DELL_ZM1] = {
18113 .mixers = { alc663_m51va_mixer },
18114 .cap_mixer = alc662_auto_capture_mixer,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018115 .init_verbs = { alc662_init_verbs,
18116 alc662_eapd_init_verbs,
18117 alc272_dell_zm1_init_verbs },
Kailang Yang622e84c2009-04-21 07:39:04 +020018118 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
Takashi Iwai1bc7cf92011-04-06 09:42:29 +020018119 .dac_nids = alc272_dac_nids,
Kailang Yang622e84c2009-04-21 07:39:04 +020018120 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18121 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018122 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018123 .capsrc_nids = alc662_capsrc_nids,
18124 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018125 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018126 .setup = alc663_m51va_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018127 .init_hook = alc_inithook,
Kailang Yang622e84c2009-04-21 07:39:04 +020018128 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018129 [ALC272_SAMSUNG_NC10] = {
18130 .mixers = { alc272_nc10_mixer },
18131 .init_verbs = { alc662_init_verbs,
Takashi Iwaia7f23712011-04-07 10:24:23 +020018132 alc662_eapd_init_verbs,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018133 alc663_21jd_amic_init_verbs },
18134 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18135 .dac_nids = alc272_dac_nids,
18136 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18137 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018138 /*.input_mux = &alc272_nc10_capture_source,*/
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018139 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018140 .setup = alc663_mode4_setup,
Takashi Iwai3b8510c2011-04-28 14:03:24 +020018141 .init_hook = alc_inithook,
Chris Pockelé9541ba12009-05-12 08:08:53 +020018142 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018143};
18144
18145
18146/*
18147 * BIOS auto configuration
18148 */
18149
Takashi Iwai7085ec12009-10-02 09:03:58 +020018150/* convert from MIX nid to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018151static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018152{
Takashi Iwai604401a2011-04-27 15:14:23 +020018153 hda_nid_t list[5];
Takashi Iwai1304ac82011-04-06 15:16:21 +020018154 int i, num;
18155
18156 num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
18157 for (i = 0; i < num; i++) {
18158 if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
18159 return list[i];
18160 }
18161 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018162}
18163
Takashi Iwai604401a2011-04-27 15:14:23 +020018164/* go down to the selector widget before the mixer */
18165static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
18166{
18167 hda_nid_t srcs[5];
18168 int num = snd_hda_get_connections(codec, pin, srcs,
18169 ARRAY_SIZE(srcs));
18170 if (num != 1 ||
18171 get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
18172 return pin;
18173 return srcs[0];
18174}
18175
Takashi Iwai7085ec12009-10-02 09:03:58 +020018176/* get MIX nid connected to the given pin targeted to DAC */
Takashi Iwai604401a2011-04-27 15:14:23 +020018177static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018178 hda_nid_t dac)
18179{
David Henningssoncc1c4522010-11-24 14:17:47 +010018180 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018181 int i, num;
18182
Takashi Iwai604401a2011-04-27 15:14:23 +020018183 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018184 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18185 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018186 if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018187 return mix[i];
18188 }
18189 return 0;
18190}
18191
Takashi Iwaice764ab2011-04-27 16:35:23 +020018192/* select the connection from pin to DAC if needed */
18193static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
18194 hda_nid_t dac)
18195{
18196 hda_nid_t mix[5];
18197 int i, num;
18198
18199 pin = alc_go_down_to_selector(codec, pin);
18200 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
18201 if (num < 2)
18202 return 0;
18203 for (i = 0; i < num; i++) {
18204 if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
18205 snd_hda_codec_update_cache(codec, pin, 0,
18206 AC_VERB_SET_CONNECT_SEL, i);
18207 return 0;
18208 }
18209 }
18210 return 0;
18211}
18212
Takashi Iwai7085ec12009-10-02 09:03:58 +020018213/* look for an empty DAC slot */
Takashi Iwai604401a2011-04-27 15:14:23 +020018214static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018215{
18216 struct alc_spec *spec = codec->spec;
18217 hda_nid_t srcs[5];
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018218 int i, num;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018219
Takashi Iwai604401a2011-04-27 15:14:23 +020018220 pin = alc_go_down_to_selector(codec, pin);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018221 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018222 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018223 hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018224 if (!nid)
18225 continue;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018226 if (found_in_nid_list(nid, spec->multiout.dac_nids,
18227 spec->multiout.num_dacs))
18228 continue;
18229 if (spec->multiout.hp_nid == nid)
18230 continue;
18231 if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
18232 ARRAY_SIZE(spec->multiout.extra_out_nid)))
18233 continue;
18234 return nid;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018235 }
18236 return 0;
18237}
18238
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018239static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
18240{
18241 hda_nid_t sel = alc_go_down_to_selector(codec, pin);
18242 if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
18243 return alc_auto_look_for_dac(codec, pin);
18244 return 0;
18245}
18246
Takashi Iwai7085ec12009-10-02 09:03:58 +020018247/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018248static int alc_auto_fill_dac_nids(struct hda_codec *codec)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018249{
18250 struct alc_spec *spec = codec->spec;
Takashi Iwaicb053a82011-06-27 11:32:07 +020018251 const struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai350434e2011-06-30 21:29:12 +020018252 bool redone = false;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018253 int i;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018254
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018255 again:
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018256 spec->multiout.num_dacs = 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018257 spec->multiout.hp_nid = 0;
18258 spec->multiout.extra_out_nid[0] = 0;
18259 memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
18260 spec->multiout.dac_nids = spec->private_dac_nids;
18261
18262 /* fill hard-wired DACs first */
18263 if (!redone) {
18264 for (i = 0; i < cfg->line_outs; i++)
18265 spec->private_dac_nids[i] =
18266 get_dac_if_single(codec, cfg->line_out_pins[i]);
18267 if (cfg->hp_outs)
18268 spec->multiout.hp_nid =
18269 get_dac_if_single(codec, cfg->hp_pins[0]);
18270 if (cfg->speaker_outs)
18271 spec->multiout.extra_out_nid[0] =
18272 get_dac_if_single(codec, cfg->speaker_pins[0]);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018273 }
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018274
18275 for (i = 0; i < cfg->line_outs; i++) {
18276 hda_nid_t pin = cfg->line_out_pins[i];
18277 if (spec->private_dac_nids[i])
18278 continue;
18279 spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
18280 if (!spec->private_dac_nids[i] && !redone) {
18281 /* if we can't find primary DACs, re-probe without
18282 * checking the hard-wired DACs
18283 */
18284 redone = true;
18285 goto again;
18286 }
18287 }
18288
18289 for (i = 0; i < cfg->line_outs; i++) {
18290 if (spec->private_dac_nids[i])
18291 spec->multiout.num_dacs++;
18292 else
18293 memmove(spec->private_dac_nids + i,
18294 spec->private_dac_nids + i + 1,
18295 sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
18296 }
18297
Takashi Iwaibb8bf4d2011-07-06 13:07:54 +020018298 if (cfg->hp_outs && !spec->multiout.hp_nid)
18299 spec->multiout.hp_nid =
18300 alc_auto_look_for_dac(codec, cfg->hp_pins[0]);
18301 if (cfg->speaker_outs && !spec->multiout.extra_out_nid[0])
18302 spec->multiout.extra_out_nid[0] =
18303 alc_auto_look_for_dac(codec, cfg->speaker_pins[0]);
18304
Takashi Iwai7085ec12009-10-02 09:03:58 +020018305 return 0;
18306}
18307
Takashi Iwai343a04b2011-07-06 14:28:39 +020018308static int alc_auto_add_vol_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +020018309 const char *pfx, int cidx,
18310 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018311{
Takashi Iwai97aaab72011-07-06 14:02:55 +020018312 return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
18313 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018314}
18315
Takashi Iwai343a04b2011-07-06 14:28:39 +020018316#define alc_auto_add_stereo_vol(codec, pfx, cidx, nid) \
18317 alc_auto_add_vol_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai97aaab72011-07-06 14:02:55 +020018318
18319/* create a mute-switch for the given mixer widget;
18320 * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
18321 */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018322static int alc_auto_add_sw_ctl(struct hda_codec *codec,
Takashi Iwai97aaab72011-07-06 14:02:55 +020018323 const char *pfx, int cidx,
18324 hda_nid_t nid, unsigned int chs)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018325{
Takashi Iwai97aaab72011-07-06 14:02:55 +020018326 int type;
18327 unsigned long val;
18328 if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
18329 type = ALC_CTL_WIDGET_MUTE;
18330 val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
18331 } else {
18332 type = ALC_CTL_BIND_MUTE;
18333 val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
18334 }
18335 return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018336}
18337
Takashi Iwai343a04b2011-07-06 14:28:39 +020018338#define alc_auto_add_stereo_sw(codec, pfx, cidx, nid) \
18339 alc_auto_add_sw_ctl(codec, pfx, cidx, nid, 3)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018340
18341/* add playback controls from the parsed DAC table */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018342static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018343 const struct auto_pin_cfg *cfg)
18344{
18345 struct alc_spec *spec = codec->spec;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018346 hda_nid_t nid, mix, pin;
18347 int i, err, noutputs;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018348
Takashi Iwaice764ab2011-04-27 16:35:23 +020018349 noutputs = cfg->line_outs;
18350 if (spec->multi_ios > 0)
18351 noutputs += spec->multi_ios;
18352
18353 for (i = 0; i < noutputs; i++) {
Takashi Iwai6843ca12011-06-24 11:03:58 +020018354 const char *name;
18355 int index;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018356 nid = spec->multiout.dac_nids[i];
18357 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018358 continue;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018359 if (i >= cfg->line_outs)
18360 pin = spec->multi_io[i - 1].pin;
18361 else
18362 pin = cfg->line_out_pins[i];
18363 mix = alc_auto_dac_to_mix(codec, pin, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018364 if (!mix)
18365 continue;
Takashi Iwai6843ca12011-06-24 11:03:58 +020018366 name = alc_get_line_out_pfx(spec, i, true, &index);
18367 if (!name) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018368 /* Center/LFE */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018369 err = alc_auto_add_vol_ctl(codec, "Center", 0, nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018370 if (err < 0)
18371 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018372 err = alc_auto_add_vol_ctl(codec, "LFE", 0, nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018373 if (err < 0)
18374 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018375 err = alc_auto_add_sw_ctl(codec, "Center", 0, mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018376 if (err < 0)
18377 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018378 err = alc_auto_add_sw_ctl(codec, "LFE", 0, mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018379 if (err < 0)
18380 return err;
18381 } else {
Takashi Iwai343a04b2011-07-06 14:28:39 +020018382 err = alc_auto_add_stereo_vol(codec, name, index, nid);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018383 if (err < 0)
18384 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018385 err = alc_auto_add_stereo_sw(codec, name, index, mix);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018386 if (err < 0)
18387 return err;
18388 }
18389 }
18390 return 0;
18391}
18392
18393/* add playback controls for speaker and HP outputs */
Takashi Iwai343a04b2011-07-06 14:28:39 +020018394static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018395 hda_nid_t dac, const char *pfx)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018396{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018397 struct alc_spec *spec = codec->spec;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018398 hda_nid_t mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018399 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018400
18401 if (!pin)
18402 return 0;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018403 if (!dac) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020018404 /* the corresponding DAC is already occupied */
18405 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
18406 return 0; /* no way */
18407 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020018408 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018409 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
18410 }
18411
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018412 mix = alc_auto_dac_to_mix(codec, pin, dac);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018413 if (!mix)
18414 return 0;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018415 err = alc_auto_add_stereo_vol(codec, pfx, 0, dac);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018416 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020018417 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018418 err = alc_auto_add_stereo_sw(codec, pfx, 0, mix);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018419 if (err < 0)
18420 return err;
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018421 return 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018422}
18423
Takashi Iwai343a04b2011-07-06 14:28:39 +020018424static int alc_auto_create_hp_out(struct hda_codec *codec)
18425{
18426 struct alc_spec *spec = codec->spec;
18427 return alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
18428 spec->multiout.hp_nid,
18429 "Headphone");
18430}
18431
18432static int alc_auto_create_speaker_out(struct hda_codec *codec)
18433{
18434 struct alc_spec *spec = codec->spec;
18435 return alc_auto_create_extra_out(codec, spec->autocfg.speaker_pins[0],
18436 spec->multiout.extra_out_nid[0],
18437 "Speaker");
18438}
18439
Takashi Iwai343a04b2011-07-06 14:28:39 +020018440static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018441 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018442 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018443{
Takashi Iwai7085ec12009-10-02 09:03:58 +020018444 int i, num;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018445 hda_nid_t mix = 0;
Takashi Iwaice503f32010-07-30 10:37:29 +020018446 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018447
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018448 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaicd511552011-07-06 13:10:42 +020018449 nid = alc_go_down_to_selector(codec, nid);
Takashi Iwai7085ec12009-10-02 09:03:58 +020018450 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
Takashi Iwai7085ec12009-10-02 09:03:58 +020018451 for (i = 0; i < num; i++) {
Takashi Iwai604401a2011-04-27 15:14:23 +020018452 if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
Takashi Iwai7085ec12009-10-02 09:03:58 +020018453 continue;
Takashi Iwaicd511552011-07-06 13:10:42 +020018454 mix = srcs[i];
18455 break;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018456 }
Takashi Iwaicd511552011-07-06 13:10:42 +020018457 if (!mix)
18458 return;
18459
18460 /* need the manual connection? */
18461 if (num > 1)
18462 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
18463 /* unmute mixer widget inputs */
18464 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18465 AMP_IN_UNMUTE(0));
18466 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18467 AMP_IN_UNMUTE(1));
18468 /* initialize volume */
18469 if (query_amp_caps(codec, dac, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
18470 nid = dac;
18471 else if (query_amp_caps(codec, mix, HDA_OUTPUT) & AC_AMPCAP_NUM_STEPS)
18472 nid = mix;
18473 else
18474 return;
18475 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
18476 AMP_OUT_ZERO);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018477}
18478
Takashi Iwai343a04b2011-07-06 14:28:39 +020018479static void alc_auto_init_multi_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018480{
18481 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020018482 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018483 int i;
18484
18485 for (i = 0; i <= HDA_SIDE; i++) {
18486 hda_nid_t nid = spec->autocfg.line_out_pins[i];
18487 if (nid)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018488 alc_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018489 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018490 }
18491}
18492
Takashi Iwai343a04b2011-07-06 14:28:39 +020018493static void alc_auto_init_extra_out(struct hda_codec *codec)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018494{
18495 struct alc_spec *spec = codec->spec;
18496 hda_nid_t pin;
18497
18498 pin = spec->autocfg.hp_pins[0];
Takashi Iwai7085ec12009-10-02 09:03:58 +020018499 if (pin)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018500 alc_auto_set_output_and_unmute(codec, pin, PIN_HP,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018501 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018502 pin = spec->autocfg.speaker_pins[0];
18503 if (pin)
Takashi Iwai343a04b2011-07-06 14:28:39 +020018504 alc_auto_set_output_and_unmute(codec, pin, PIN_OUT,
Takashi Iwai7085ec12009-10-02 09:03:58 +020018505 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018506}
18507
Takashi Iwaice764ab2011-04-27 16:35:23 +020018508/*
18509 * multi-io helper
18510 */
18511static int alc_auto_fill_multi_ios(struct hda_codec *codec,
18512 unsigned int location)
18513{
18514 struct alc_spec *spec = codec->spec;
18515 struct auto_pin_cfg *cfg = &spec->autocfg;
18516 int type, i, num_pins = 0;
18517
18518 for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
18519 for (i = 0; i < cfg->num_inputs; i++) {
18520 hda_nid_t nid = cfg->inputs[i].pin;
18521 hda_nid_t dac;
18522 unsigned int defcfg, caps;
18523 if (cfg->inputs[i].type != type)
18524 continue;
18525 defcfg = snd_hda_codec_get_pincfg(codec, nid);
18526 if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
18527 continue;
18528 if (location && get_defcfg_location(defcfg) != location)
18529 continue;
18530 caps = snd_hda_query_pin_caps(codec, nid);
18531 if (!(caps & AC_PINCAP_OUT))
18532 continue;
18533 dac = alc_auto_look_for_dac(codec, nid);
18534 if (!dac)
18535 continue;
18536 spec->multi_io[num_pins].pin = nid;
18537 spec->multi_io[num_pins].dac = dac;
18538 num_pins++;
Takashi Iwaidda14412011-05-02 11:29:30 +020018539 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Takashi Iwaice764ab2011-04-27 16:35:23 +020018540 }
18541 }
18542 spec->multiout.num_dacs = 1;
18543 if (num_pins < 2)
18544 return 0;
18545 return num_pins;
18546}
18547
18548static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
18549 struct snd_ctl_elem_info *uinfo)
18550{
18551 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18552 struct alc_spec *spec = codec->spec;
18553
18554 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
18555 uinfo->count = 1;
18556 uinfo->value.enumerated.items = spec->multi_ios + 1;
18557 if (uinfo->value.enumerated.item > spec->multi_ios)
18558 uinfo->value.enumerated.item = spec->multi_ios;
18559 sprintf(uinfo->value.enumerated.name, "%dch",
18560 (uinfo->value.enumerated.item + 1) * 2);
18561 return 0;
18562}
18563
18564static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
18565 struct snd_ctl_elem_value *ucontrol)
18566{
18567 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18568 struct alc_spec *spec = codec->spec;
18569 ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
18570 return 0;
18571}
18572
18573static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
18574{
18575 struct alc_spec *spec = codec->spec;
18576 hda_nid_t nid = spec->multi_io[idx].pin;
18577
18578 if (!spec->multi_io[idx].ctl_in)
18579 spec->multi_io[idx].ctl_in =
18580 snd_hda_codec_read(codec, nid, 0,
18581 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
18582 if (output) {
18583 snd_hda_codec_update_cache(codec, nid, 0,
18584 AC_VERB_SET_PIN_WIDGET_CONTROL,
18585 PIN_OUT);
18586 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
18587 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
18588 HDA_AMP_MUTE, 0);
18589 alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
18590 } else {
18591 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
18592 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
18593 HDA_AMP_MUTE, HDA_AMP_MUTE);
18594 snd_hda_codec_update_cache(codec, nid, 0,
18595 AC_VERB_SET_PIN_WIDGET_CONTROL,
18596 spec->multi_io[idx].ctl_in);
18597 }
18598 return 0;
18599}
18600
18601static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
18602 struct snd_ctl_elem_value *ucontrol)
18603{
18604 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
18605 struct alc_spec *spec = codec->spec;
18606 int i, ch;
18607
18608 ch = ucontrol->value.enumerated.item[0];
18609 if (ch < 0 || ch > spec->multi_ios)
18610 return -EINVAL;
18611 if (ch == (spec->ext_channel_count - 1) / 2)
18612 return 0;
18613 spec->ext_channel_count = (ch + 1) * 2;
18614 for (i = 0; i < spec->multi_ios; i++)
18615 alc_set_multi_io(codec, i, i < ch);
18616 spec->multiout.max_channels = spec->ext_channel_count;
18617 return 1;
18618}
18619
Takashi Iwaia9111322011-05-02 11:30:18 +020018620static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
Takashi Iwaice764ab2011-04-27 16:35:23 +020018621 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
18622 .name = "Channel Mode",
18623 .info = alc_auto_ch_mode_info,
18624 .get = alc_auto_ch_mode_get,
18625 .put = alc_auto_ch_mode_put,
18626};
18627
Takashi Iwaicb053a82011-06-27 11:32:07 +020018628static int alc_auto_add_multi_channel_mode(struct hda_codec *codec,
18629 int (*fill_dac)(struct hda_codec *))
Takashi Iwaice764ab2011-04-27 16:35:23 +020018630{
18631 struct alc_spec *spec = codec->spec;
18632 struct auto_pin_cfg *cfg = &spec->autocfg;
18633 unsigned int location, defcfg;
18634 int num_pins;
18635
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018636 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && cfg->hp_outs == 1) {
18637 /* use HP as primary out */
18638 cfg->speaker_outs = cfg->line_outs;
18639 memcpy(cfg->speaker_pins, cfg->line_out_pins,
18640 sizeof(cfg->speaker_pins));
18641 cfg->line_outs = cfg->hp_outs;
18642 memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
18643 cfg->hp_outs = 0;
18644 memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
18645 cfg->line_out_type = AUTO_PIN_HP_OUT;
Takashi Iwaicb053a82011-06-27 11:32:07 +020018646 if (fill_dac)
18647 fill_dac(codec);
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018648 }
Takashi Iwaice764ab2011-04-27 16:35:23 +020018649 if (cfg->line_outs != 1 ||
Takashi Iwai3fccdfd2011-06-24 10:35:05 +020018650 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
Takashi Iwaice764ab2011-04-27 16:35:23 +020018651 return 0;
18652
18653 defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
18654 location = get_defcfg_location(defcfg);
18655
18656 num_pins = alc_auto_fill_multi_ios(codec, location);
18657 if (num_pins > 0) {
18658 struct snd_kcontrol_new *knew;
18659
18660 knew = alc_kcontrol_new(spec);
18661 if (!knew)
18662 return -ENOMEM;
18663 *knew = alc_auto_channel_mode_enum;
18664 knew->name = kstrdup("Channel Mode", GFP_KERNEL);
18665 if (!knew->name)
18666 return -ENOMEM;
18667
18668 spec->multi_ios = num_pins;
18669 spec->ext_channel_count = 2;
18670 spec->multiout.num_dacs = num_pins + 1;
18671 }
18672 return 0;
18673}
18674
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018675static int alc662_parse_auto_config(struct hda_codec *codec)
18676{
18677 struct alc_spec *spec = codec->spec;
18678 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020018679 static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018680
18681 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
18682 alc662_ignore);
18683 if (err < 0)
18684 return err;
18685 if (!spec->autocfg.line_outs)
18686 return 0; /* can't find valid BIOS pin config */
18687
Takashi Iwai343a04b2011-07-06 14:28:39 +020018688 err = alc_auto_fill_dac_nids(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018689 if (err < 0)
18690 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018691 err = alc_auto_add_multi_channel_mode(codec, alc_auto_fill_dac_nids);
Takashi Iwaice764ab2011-04-27 16:35:23 +020018692 if (err < 0)
18693 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018694 err = alc_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018695 if (err < 0)
18696 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018697 err = alc_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018698 spec->autocfg.speaker_pins[0],
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018699 spec->multiout.extra_out_nid[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018700 "Speaker");
18701 if (err < 0)
18702 return err;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018703 err = alc_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwai3af9ee62011-06-27 12:34:01 +020018704 spec->multiout.hp_nid,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018705 "Headphone");
18706 if (err < 0)
18707 return err;
Takashi Iwaib7821702011-07-06 15:12:46 +020018708 err = alc_auto_create_input_ctls(codec);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018709 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018710 return err;
18711
18712 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
18713
Takashi Iwai757899a2010-07-30 10:48:14 +020018714 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018715
Takashi Iwai603c4012008-07-30 15:01:44 +020018716 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010018717 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018718
Takashi Iwai21268962011-07-07 15:01:13 +020018719 alc_remove_invalid_adc_nids(codec);
Takashi Iwaiee979a142008-09-02 15:42:20 +020018720
Kailang Yang6227cdc2010-02-25 08:36:52 +010018721 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
18722 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
18723 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
18724 else
18725 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai21268962011-07-07 15:01:13 +020018726 alc_auto_check_switches(codec);
18727
18728 err = alc_auto_add_mic_boost(codec);
18729 if (err < 0)
18730 return err;
Takashi Iwai4a79ba32009-04-22 16:31:35 +020018731
Takashi Iwai8c872862007-06-19 12:11:16 +020018732 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018733}
18734
18735/* additional initialization for auto-configuration model */
18736static void alc662_auto_init(struct hda_codec *codec)
18737{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018738 struct alc_spec *spec = codec->spec;
Takashi Iwai343a04b2011-07-06 14:28:39 +020018739 alc_auto_init_multi_out(codec);
18740 alc_auto_init_extra_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020018741 alc_auto_init_analog_input(codec);
Takashi Iwaif970de22011-07-06 17:39:59 +020018742 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020018743 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010018744 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020018745 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018746}
18747
Todd Broch6be79482010-12-07 16:51:05 -080018748static void alc272_fixup_mario(struct hda_codec *codec,
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018749 const struct alc_fixup *fix, int action)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010018750{
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018751 if (action != ALC_FIXUP_ACT_PROBE)
Takashi Iwai6fc398c2011-01-13 14:36:37 +010018752 return;
Todd Broch6be79482010-12-07 16:51:05 -080018753 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
18754 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
18755 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
18756 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
18757 (0 << AC_AMPCAP_MUTE_SHIFT)))
18758 printk(KERN_WARNING
18759 "hda_codec: failed to override amp caps for NID 0x2\n");
18760}
18761
David Henningsson6cb3b702010-09-09 08:51:44 +020018762enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040018763 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020018764 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080018765 ALC272_FIXUP_MARIO,
Anisse Astierd2ebd472011-01-20 12:36:21 +010018766 ALC662_FIXUP_CZC_P10T,
David Henningsson94024cd2011-04-29 14:10:55 +020018767 ALC662_FIXUP_SKU_IGNORE,
David Henningsson6cb3b702010-09-09 08:51:44 +020018768};
18769
18770static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040018771 [ALC662_FIXUP_ASPIRE] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018772 .type = ALC_FIXUP_PINS,
18773 .v.pins = (const struct alc_pincfg[]) {
Daniel T Chen2df03512010-10-10 22:39:28 -040018774 { 0x15, 0x99130112 }, /* subwoofer */
18775 { }
18776 }
18777 },
David Henningsson6cb3b702010-09-09 08:51:44 +020018778 [ALC662_FIXUP_IDEAPAD] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018779 .type = ALC_FIXUP_PINS,
18780 .v.pins = (const struct alc_pincfg[]) {
David Henningsson6cb3b702010-09-09 08:51:44 +020018781 { 0x17, 0x99130112 }, /* subwoofer */
18782 { }
18783 }
18784 },
Todd Broch6be79482010-12-07 16:51:05 -080018785 [ALC272_FIXUP_MARIO] = {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018786 .type = ALC_FIXUP_FUNC,
18787 .v.func = alc272_fixup_mario,
Anisse Astierd2ebd472011-01-20 12:36:21 +010018788 },
18789 [ALC662_FIXUP_CZC_P10T] = {
18790 .type = ALC_FIXUP_VERBS,
18791 .v.verbs = (const struct hda_verb[]) {
18792 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
18793 {}
18794 }
18795 },
David Henningsson94024cd2011-04-29 14:10:55 +020018796 [ALC662_FIXUP_SKU_IGNORE] = {
18797 .type = ALC_FIXUP_SKU,
18798 .v.sku = ALC_FIXUP_SKU_IGNORE,
Takashi Iwaic6b35872011-03-28 12:05:31 +020018799 },
David Henningsson6cb3b702010-09-09 08:51:44 +020018800};
18801
Takashi Iwaia9111322011-05-02 11:30:18 +020018802static const struct snd_pci_quirk alc662_fixup_tbl[] = {
David Henningssona6c47a82011-02-10 15:39:19 +010018803 SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
David Henningsson94024cd2011-04-29 14:10:55 +020018804 SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
Daniel T Chen2df03512010-10-10 22:39:28 -040018805 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050018806 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060018807 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020018808 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
Anisse Astierd2ebd472011-01-20 12:36:21 +010018809 SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
David Henningsson6cb3b702010-09-09 08:51:44 +020018810 {}
18811};
18812
Todd Broch6be79482010-12-07 16:51:05 -080018813static const struct alc_model_fixup alc662_fixup_models[] = {
18814 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
18815 {}
18816};
David Henningsson6cb3b702010-09-09 08:51:44 +020018817
18818
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018819static int patch_alc662(struct hda_codec *codec)
18820{
18821 struct alc_spec *spec;
18822 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020018823 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018824
18825 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
18826 if (!spec)
18827 return -ENOMEM;
18828
18829 codec->spec = spec;
18830
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020018831 spec->mixer_nid = 0x0b;
18832
Kailang Yangda00c242010-03-19 11:23:45 +010018833 alc_auto_parse_customize_define(codec);
18834
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020018835 alc_fix_pll_init(codec, 0x20, 0x04, 15);
18836
Kailang Yang693194f2010-10-21 08:51:48 +020018837 coef = alc_read_coef_idx(codec, 0);
18838 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010018839 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020018840 else if (coef & (1 << 14) &&
18841 codec->bus->pci->subsystem_vendor == 0x1025 &&
18842 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010018843 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020018844 else if (coef == 0x4011)
18845 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010018846
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018847 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
18848 alc662_models,
18849 alc662_cfg_tbl);
18850 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020018851 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
18852 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018853 board_config = ALC662_AUTO;
18854 }
18855
18856 if (board_config == ALC662_AUTO) {
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018857 alc_pick_fixup(codec, alc662_fixup_models,
18858 alc662_fixup_tbl, alc662_fixups);
18859 alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018860 /* automatic parse from the BIOS config */
18861 err = alc662_parse_auto_config(codec);
18862 if (err < 0) {
18863 alc_free(codec);
18864 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020018865 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018866 printk(KERN_INFO
18867 "hda_codec: Cannot set up configuration "
18868 "from BIOS. Using base mode...\n");
18869 board_config = ALC662_3ST_2ch_DIG;
18870 }
18871 }
18872
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018873 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020018874 err = snd_hda_attach_beep_device(codec, 0x1);
18875 if (err < 0) {
18876 alc_free(codec);
18877 return err;
18878 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090018879 }
18880
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018881 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020018882 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018883
Takashi Iwaidd704692009-08-11 08:45:11 +020018884 if (!spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020018885 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020018886 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020018887 alc_remove_invalid_adc_nids(codec);
Takashi Iwaidd704692009-08-11 08:45:11 +020018888 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018889
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018890 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018891 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018892
Takashi Iwaidc1eae22010-07-29 15:30:02 +020018893 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010018894 switch (codec->vendor_id) {
18895 case 0x10ec0662:
18896 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
18897 break;
18898 case 0x10ec0272:
18899 case 0x10ec0663:
18900 case 0x10ec0665:
18901 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
18902 break;
18903 case 0x10ec0273:
18904 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
18905 break;
18906 }
Kailang Yangcec27c82010-02-04 14:18:18 +010018907 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010018908 spec->vmaster_nid = 0x02;
18909
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018910 alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
18911
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018912 codec->patch_ops = alc_patch_ops;
Takashi Iwaib5bfbc62011-01-13 14:22:32 +010018913 if (board_config == ALC662_AUTO)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018914 spec->init_hook = alc662_auto_init;
Takashi Iwai1c716152011-04-07 10:37:16 +020018915 spec->shutup = alc_eapd_shutup;
David Henningsson6cb3b702010-09-09 08:51:44 +020018916
Kailang Yangbf1b0222010-10-21 08:49:56 +020018917 alc_init_jacks(codec);
18918
Takashi Iwaicb53c622007-08-10 17:21:45 +020018919#ifdef CONFIG_SND_HDA_POWER_SAVE
18920 if (!spec->loopback.amplist)
18921 spec->loopback.amplist = alc662_loopbacks;
18922#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018923
18924 return 0;
18925}
18926
Kailang Yang274693f2009-12-03 10:07:50 +010018927static int patch_alc888(struct hda_codec *codec)
18928{
18929 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
18930 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010018931 if (codec->vendor_id == 0x10ec0887)
18932 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
18933 else
18934 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018935 if (!codec->chip_name) {
18936 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018937 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018938 }
18939 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018940 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010018941 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010018942}
18943
Kailang Yangb478b992011-05-18 11:51:15 +020018944static int patch_alc899(struct hda_codec *codec)
18945{
18946 if ((alc_read_coef_idx(codec, 0) & 0x2000) != 0x2000) {
18947 kfree(codec->chip_name);
18948 codec->chip_name = kstrdup("ALC898", GFP_KERNEL);
18949 }
18950 return patch_alc882(codec);
18951}
18952
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018953/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018954 * ALC680 support
18955 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020018956#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018957#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
18958#define alc680_modes alc260_modes
18959
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020018960static const hda_nid_t alc680_dac_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018961 /* Lout1, Lout2, hp */
18962 0x02, 0x03, 0x04
18963};
18964
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020018965static const hda_nid_t alc680_adc_nids[3] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020018966 /* ADC0-2 */
18967 /* DMIC, MIC, Line-in*/
18968 0x07, 0x08, 0x09
18969};
18970
Kailang Yangc69aefa2010-08-17 10:39:22 +020018971/*
18972 * Analog capture ADC cgange
18973 */
Takashi Iwai21268962011-07-07 15:01:13 +020018974static hda_nid_t alc680_get_cur_adc(struct hda_codec *codec)
18975{
18976 static hda_nid_t pins[] = {0x18, 0x19};
18977 static hda_nid_t adcs[] = {0x08, 0x09};
18978 int i;
18979
18980 for (i = 0; i < ARRAY_SIZE(pins); i++) {
18981 if (!is_jack_detectable(codec, pins[i]))
18982 continue;
18983 if (snd_hda_jack_detect(codec, pins[i]))
18984 return adcs[i];
18985 }
18986 return 0x07;
18987}
18988
Takashi Iwai66ceeb62010-08-30 13:05:52 +020018989static void alc680_rec_autoswitch(struct hda_codec *codec)
18990{
18991 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +020018992 hda_nid_t nid = alc680_get_cur_adc(codec);
18993 if (spec->cur_adc && nid != spec->cur_adc) {
Takashi Iwai66ceeb62010-08-30 13:05:52 +020018994 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai21268962011-07-07 15:01:13 +020018995 spec->cur_adc = nid;
18996 snd_hda_codec_setup_stream(codec, nid,
18997 spec->cur_adc_stream_tag, 0,
18998 spec->cur_adc_format);
18999 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019000}
19001
Kailang Yangc69aefa2010-08-17 10:39:22 +020019002static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19003 struct hda_codec *codec,
19004 unsigned int stream_tag,
19005 unsigned int format,
19006 struct snd_pcm_substream *substream)
19007{
19008 struct alc_spec *spec = codec->spec;
Takashi Iwai21268962011-07-07 15:01:13 +020019009 hda_nid_t nid = alc680_get_cur_adc(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019010
Takashi Iwai21268962011-07-07 15:01:13 +020019011 spec->cur_adc = nid;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019012 spec->cur_adc_stream_tag = stream_tag;
19013 spec->cur_adc_format = format;
Takashi Iwai21268962011-07-07 15:01:13 +020019014 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019015 return 0;
19016}
19017
19018static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19019 struct hda_codec *codec,
19020 struct snd_pcm_substream *substream)
19021{
Takashi Iwai21268962011-07-07 15:01:13 +020019022 struct alc_spec *spec = codec->spec;
19023 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
19024 spec->cur_adc = 0;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019025 return 0;
19026}
19027
Takashi Iwaia9111322011-05-02 11:30:18 +020019028static const struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019029 .substreams = 1, /* can be overridden */
19030 .channels_min = 2,
19031 .channels_max = 2,
19032 /* NID is set in alc_build_pcms */
19033 .ops = {
19034 .prepare = alc680_capture_pcm_prepare,
19035 .cleanup = alc680_capture_pcm_cleanup
19036 },
19037};
19038
Takashi Iwaia9111322011-05-02 11:30:18 +020019039static const struct snd_kcontrol_new alc680_base_mixer[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019040 /* output mixer control */
19041 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19042 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19043 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19044 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019045 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19046 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19047 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019048 { }
19049};
19050
Takashi Iwaia9111322011-05-02 11:30:18 +020019051static const struct hda_bind_ctls alc680_bind_cap_vol = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019052 .ops = &snd_hda_bind_vol,
19053 .values = {
19054 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19055 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19056 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19057 0
19058 },
19059};
19060
Takashi Iwaia9111322011-05-02 11:30:18 +020019061static const struct hda_bind_ctls alc680_bind_cap_switch = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019062 .ops = &snd_hda_bind_sw,
19063 .values = {
19064 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19065 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19066 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19067 0
19068 },
19069};
19070
Takashi Iwaia9111322011-05-02 11:30:18 +020019071static const struct snd_kcontrol_new alc680_master_capture_mixer[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019072 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19073 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019074 { } /* end */
19075};
19076
19077/*
19078 * generic initialization of ADC, input mixers and output mixers
19079 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019080static const struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019081 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19082 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19083 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019084
Kailang Yangc69aefa2010-08-17 10:39:22 +020019085 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19086 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19087 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19088 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19089 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19090 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019091
19092 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19093 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19094 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19095 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19096 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019097
19098 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19099 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019100 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019101
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019102 { }
19103};
19104
Kailang Yangc69aefa2010-08-17 10:39:22 +020019105/* toggle speaker-output according to the hp-jack state */
19106static void alc680_base_setup(struct hda_codec *codec)
19107{
19108 struct alc_spec *spec = codec->spec;
19109
19110 spec->autocfg.hp_pins[0] = 0x16;
19111 spec->autocfg.speaker_pins[0] = 0x14;
19112 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019113 spec->autocfg.num_inputs = 2;
19114 spec->autocfg.inputs[0].pin = 0x18;
19115 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19116 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019117 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Takashi Iwaid922b512011-04-28 12:18:53 +020019118 spec->automute = 1;
19119 spec->automute_mode = ALC_AUTOMUTE_AMP;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019120}
19121
19122static void alc680_unsol_event(struct hda_codec *codec,
19123 unsigned int res)
19124{
19125 if ((res >> 26) == ALC880_HP_EVENT)
Takashi Iwaid922b512011-04-28 12:18:53 +020019126 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019127 if ((res >> 26) == ALC880_MIC_EVENT)
19128 alc680_rec_autoswitch(codec);
19129}
19130
19131static void alc680_inithook(struct hda_codec *codec)
19132{
Takashi Iwaid922b512011-04-28 12:18:53 +020019133 alc_hp_automute(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019134 alc680_rec_autoswitch(codec);
19135}
19136
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019137/* create input playback/capture controls for the given pin */
19138static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19139 const char *ctlname, int idx)
19140{
19141 hda_nid_t dac;
19142 int err;
19143
19144 switch (nid) {
19145 case 0x14:
19146 dac = 0x02;
19147 break;
19148 case 0x15:
19149 dac = 0x03;
19150 break;
19151 case 0x16:
19152 dac = 0x04;
19153 break;
19154 default:
19155 return 0;
19156 }
19157 if (spec->multiout.dac_nids[0] != dac &&
19158 spec->multiout.dac_nids[1] != dac) {
19159 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19160 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19161 HDA_OUTPUT));
19162 if (err < 0)
19163 return err;
19164
19165 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19166 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19167
19168 if (err < 0)
19169 return err;
Takashi Iwaidda14412011-05-02 11:29:30 +020019170 spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019171 }
19172
19173 return 0;
19174}
19175
19176/* add playback controls from the parsed DAC table */
19177static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19178 const struct auto_pin_cfg *cfg)
19179{
19180 hda_nid_t nid;
19181 int err;
19182
19183 spec->multiout.dac_nids = spec->private_dac_nids;
19184
19185 nid = cfg->line_out_pins[0];
19186 if (nid) {
19187 const char *name;
Takashi Iwai2e925dd2011-06-24 11:27:22 +020019188 int index;
19189 name = alc_get_line_out_pfx(spec, 0, true, &index);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019190 err = alc680_new_analog_output(spec, nid, name, 0);
19191 if (err < 0)
19192 return err;
19193 }
19194
19195 nid = cfg->speaker_pins[0];
19196 if (nid) {
19197 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19198 if (err < 0)
19199 return err;
19200 }
19201 nid = cfg->hp_pins[0];
19202 if (nid) {
19203 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19204 if (err < 0)
19205 return err;
19206 }
19207
19208 return 0;
19209}
19210
19211static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19212 hda_nid_t nid, int pin_type)
19213{
19214 alc_set_pin_output(codec, nid, pin_type);
19215}
19216
19217static void alc680_auto_init_multi_out(struct hda_codec *codec)
19218{
19219 struct alc_spec *spec = codec->spec;
19220 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19221 if (nid) {
19222 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19223 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19224 }
19225}
19226
19227static void alc680_auto_init_hp_out(struct hda_codec *codec)
19228{
19229 struct alc_spec *spec = codec->spec;
19230 hda_nid_t pin;
19231
19232 pin = spec->autocfg.hp_pins[0];
19233 if (pin)
19234 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19235 pin = spec->autocfg.speaker_pins[0];
19236 if (pin)
19237 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19238}
19239
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019240/*
19241 * BIOS auto configuration
19242 */
19243static int alc680_parse_auto_config(struct hda_codec *codec)
19244{
19245 struct alc_spec *spec = codec->spec;
19246 int err;
Takashi Iwai4c6d72d2011-05-02 11:30:18 +020019247 static const hda_nid_t alc680_ignore[] = { 0 };
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019248
19249 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19250 alc680_ignore);
19251 if (err < 0)
19252 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019253
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019254 if (!spec->autocfg.line_outs) {
19255 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19256 spec->multiout.max_channels = 2;
19257 spec->no_analog = 1;
19258 goto dig_only;
19259 }
19260 return 0; /* can't find valid BIOS pin config */
19261 }
19262 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19263 if (err < 0)
19264 return err;
19265
Takashi Iwai21268962011-07-07 15:01:13 +020019266 err = alc_auto_create_input_ctls(codec);
19267 if (err < 0)
19268 return err;
19269
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019270 spec->multiout.max_channels = 2;
19271
19272 dig_only:
19273 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019274 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019275 if (spec->kctls.list)
19276 add_mixer(spec, spec->kctls.list);
19277
Takashi Iwai21268962011-07-07 15:01:13 +020019278 alc_remove_invalid_adc_nids(codec);
19279
19280 alc_auto_check_switches(codec);
19281
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019282 err = alc_auto_add_mic_boost(codec);
19283 if (err < 0)
19284 return err;
19285
19286 return 1;
19287}
19288
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019289/* init callback for auto-configuration model -- overriding the default init */
19290static void alc680_auto_init(struct hda_codec *codec)
19291{
19292 struct alc_spec *spec = codec->spec;
19293 alc680_auto_init_multi_out(codec);
19294 alc680_auto_init_hp_out(codec);
Takashi Iwai0a7f5322011-07-06 15:15:12 +020019295 alc_auto_init_analog_input(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020019296 alc_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019297 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019298 if (spec->unsol_event)
19299 alc_inithook(codec);
19300}
19301
19302/*
19303 * configuration and preset
19304 */
Takashi Iwaiea734962011-01-17 11:29:34 +010019305static const char * const alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019306 [ALC680_BASE] = "base",
19307 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019308};
19309
Takashi Iwaia9111322011-05-02 11:30:18 +020019310static const struct snd_pci_quirk alc680_cfg_tbl[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019311 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19312 {}
19313};
19314
Takashi Iwaia9111322011-05-02 11:30:18 +020019315static const struct alc_config_preset alc680_presets[] = {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019316 [ALC680_BASE] = {
19317 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020019318 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019319 .init_verbs = { alc680_init_verbs },
19320 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19321 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019322 .dig_out_nid = ALC680_DIGOUT_NID,
19323 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19324 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020019325 .unsol_event = alc680_unsol_event,
19326 .setup = alc680_base_setup,
19327 .init_hook = alc680_inithook,
19328
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019329 },
19330};
19331
19332static int patch_alc680(struct hda_codec *codec)
19333{
19334 struct alc_spec *spec;
19335 int board_config;
19336 int err;
19337
19338 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19339 if (spec == NULL)
19340 return -ENOMEM;
19341
19342 codec->spec = spec;
19343
Takashi Iwai1f0f4b82011-06-27 10:52:59 +020019344 /* ALC680 has no aa-loopback mixer */
19345
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019346 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19347 alc680_models,
19348 alc680_cfg_tbl);
19349
19350 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19351 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19352 codec->chip_name);
19353 board_config = ALC680_AUTO;
19354 }
19355
19356 if (board_config == ALC680_AUTO) {
19357 /* automatic parse from the BIOS config */
19358 err = alc680_parse_auto_config(codec);
19359 if (err < 0) {
19360 alc_free(codec);
19361 return err;
19362 } else if (!err) {
19363 printk(KERN_INFO
19364 "hda_codec: Cannot set up configuration "
19365 "from BIOS. Using base mode...\n");
19366 board_config = ALC680_BASE;
19367 }
19368 }
19369
Takashi Iwai21268962011-07-07 15:01:13 +020019370 if (board_config != ALC680_AUTO) {
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019371 setup_preset(codec, &alc680_presets[board_config]);
Takashi Iwai21268962011-07-07 15:01:13 +020019372 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
19373 }
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019374
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019375 if (!spec->adc_nids) {
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020019376 alc_auto_fill_adc_caps(codec);
Takashi Iwai21268962011-07-07 15:01:13 +020019377 alc_rebuild_imux_for_auto_mic(codec);
Takashi Iwaid6cc9fab2011-07-06 16:38:42 +020019378 alc_remove_invalid_adc_nids(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019379 }
19380
19381 if (!spec->cap_mixer)
19382 set_capture_mixer(codec);
19383
19384 spec->vmaster_nid = 0x02;
19385
19386 codec->patch_ops = alc_patch_ops;
19387 if (board_config == ALC680_AUTO)
19388 spec->init_hook = alc680_auto_init;
19389
19390 return 0;
19391}
19392
19393/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019394 * patch entries
19395 */
Takashi Iwaia9111322011-05-02 11:30:18 +020019396static const struct hda_codec_preset snd_hda_preset_realtek[] = {
Kailang Yang296f0332011-05-18 11:52:36 +020019397 { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019398 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019399 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019400 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019401 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019402 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019403 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019404 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019405 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Kailang Yang296f0332011-05-18 11:52:36 +020019406 { .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019407 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019408 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019409 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19410 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19411 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019412 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020019413 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019414 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19415 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019416 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019417 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019418 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019419 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019420 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019421 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019422 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019423 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019424 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019425 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019426 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019427 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010019428 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020019429 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020019430 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019431 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020019432 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010019433 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Kailang Yangb478b992011-05-18 11:51:15 +020019434 { .id = 0x10ec0899, .name = "ALC899", .patch = patch_alc899 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019435 {} /* terminator */
19436};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019437
19438MODULE_ALIAS("snd-hda-codec-id:10ec*");
19439
19440MODULE_LICENSE("GPL");
19441MODULE_DESCRIPTION("Realtek HD-audio codec");
19442
19443static struct hda_codec_preset_list realtek_list = {
19444 .preset = snd_hda_preset_realtek,
19445 .owner = THIS_MODULE,
19446};
19447
19448static int __init patch_realtek_init(void)
19449{
19450 return snd_hda_add_codec_preset(&realtek_list);
19451}
19452
19453static void __exit patch_realtek_exit(void)
19454{
19455 snd_hda_delete_codec_preset(&realtek_list);
19456}
19457
19458module_init(patch_realtek_init)
19459module_exit(patch_realtek_exit)