blob: b4f78952381a911e2cdb0ce7aa2aa906a013a7a1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Universal Interface for Intel High Definition Audio Codec
3 *
4 * HD audio interface patch for ALC 260/880/882 codecs
5 *
Kailang Yangdf694da2005-12-05 19:42:22 +01006 * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
7 * PeiSen Hou <pshou@realtek.com.tw>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * Takashi Iwai <tiwai@suse.de>
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01009 * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
11 * This driver is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/init.h>
27#include <linux/delay.h>
28#include <linux/slab.h>
29#include <linux/pci.h>
30#include <sound/core.h>
Kailang Yang9ad0e492010-09-14 23:22:00 +020031#include <sound/jack.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "hda_codec.h"
33#include "hda_local.h"
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090034#include "hda_beep.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Kailang Yangccc656c2006-10-17 12:32:26 +020036#define ALC880_FRONT_EVENT 0x01
37#define ALC880_DCVOL_EVENT 0x02
38#define ALC880_HP_EVENT 0x04
39#define ALC880_MIC_EVENT 0x08
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* ALC880 board config type */
42enum {
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 ALC880_3ST,
44 ALC880_3ST_DIG,
45 ALC880_5ST,
46 ALC880_5ST_DIG,
47 ALC880_W810,
Takashi Iwaidfc0ff62005-05-12 14:31:49 +020048 ALC880_Z71V,
Takashi Iwaib6482d42005-06-27 15:32:43 +020049 ALC880_6ST,
Takashi Iwai16ded522005-06-10 19:58:24 +020050 ALC880_6ST_DIG,
51 ALC880_F1734,
52 ALC880_ASUS,
53 ALC880_ASUS_DIG,
54 ALC880_ASUS_W1V,
Kailang Yangdf694da2005-12-05 19:42:22 +010055 ALC880_ASUS_DIG2,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +010056 ALC880_FUJITSU,
Takashi Iwai16ded522005-06-10 19:58:24 +020057 ALC880_UNIWILL_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +020058 ALC880_UNIWILL,
59 ALC880_UNIWILL_P53,
Kailang Yangdf694da2005-12-05 19:42:22 +010060 ALC880_CLEVO,
61 ALC880_TCL_S700,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010062 ALC880_LG,
Takashi Iwaid6815182006-03-23 16:06:23 +010063 ALC880_LG_LW,
Takashi Iwaidf99cd32008-04-25 15:25:04 +020064 ALC880_MEDION_RIM,
Takashi Iwaie9edcee2005-06-13 14:16:38 +020065#ifdef CONFIG_SND_DEBUG
66 ALC880_TEST,
67#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010068 ALC880_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020069 ALC880_MODEL_LAST /* last tag */
70};
71
72/* ALC260 models */
73enum {
74 ALC260_BASIC,
75 ALC260_HP,
Kailang Yang3f878302008-08-26 13:02:23 +020076 ALC260_HP_DC7600,
Kailang Yangdf694da2005-12-05 19:42:22 +010077 ALC260_HP_3013,
78 ALC260_FUJITSU_S702X,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +010079 ALC260_ACER,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020080 ALC260_WILL,
81 ALC260_REPLACER_672V,
Michael Schwingencc959482009-02-22 18:58:45 +010082 ALC260_FAVORIT100,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +010083#ifdef CONFIG_SND_DEBUG
84 ALC260_TEST,
85#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010086 ALC260_AUTO,
Takashi Iwai16ded522005-06-10 19:58:24 +020087 ALC260_MODEL_LAST /* last tag */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088};
89
Kailang Yangdf694da2005-12-05 19:42:22 +010090/* ALC262 models */
91enum {
92 ALC262_BASIC,
Kailang Yangccc656c2006-10-17 12:32:26 +020093 ALC262_HIPPO,
94 ALC262_HIPPO_1,
Takashi Iwai834be882006-03-01 14:16:17 +010095 ALC262_FUJITSU,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020096 ALC262_HP_BPC,
Kailang Yangcd7509a2007-01-26 18:33:17 +010097 ALC262_HP_BPC_D7000_WL,
98 ALC262_HP_BPC_D7000_WF,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010099 ALC262_HP_TC_T5735,
Kailang Yang8c427222008-01-10 13:03:59 +0100100 ALC262_HP_RP5700,
Takashi Iwai304dcaa2006-07-25 14:51:16 +0200101 ALC262_BENQ_ED8,
Kailang Yang272a5272007-05-14 11:00:38 +0200102 ALC262_SONY_ASSAMD,
Kailang Yang83c34212007-07-05 11:43:05 +0200103 ALC262_BENQ_T31,
Tobin Davisf651b502007-10-26 12:40:47 +0200104 ALC262_ULTRA,
Jiang zhe0e31daf2008-03-20 12:12:39 +0100105 ALC262_LENOVO_3000,
Pascal Terjane8f9ae22008-08-04 14:36:05 +0200106 ALC262_NEC,
Kailang Yang4e555fe2008-08-26 13:05:55 +0200107 ALC262_TOSHIBA_S06,
Hiroshi Miura9f99a632008-08-28 16:09:06 +0200108 ALC262_TOSHIBA_RX1,
Tony Vroonba340e82009-02-02 19:01:30 +0000109 ALC262_TYAN,
Kailang Yangdf694da2005-12-05 19:42:22 +0100110 ALC262_AUTO,
111 ALC262_MODEL_LAST /* last tag */
112};
113
Kailang Yanga361d842007-06-05 12:30:55 +0200114/* ALC268 models */
115enum {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +0200116 ALC267_QUANTA_IL1,
Kailang Yanga361d842007-06-05 12:30:55 +0200117 ALC268_3ST,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200118 ALC268_TOSHIBA,
Takashi Iwaid2738092007-08-16 14:59:45 +0200119 ALC268_ACER,
Takashi Iwaic238b4f2008-11-05 14:57:20 +0100120 ALC268_ACER_DMIC,
Kailang Yang8ef355d2008-08-26 13:10:22 +0200121 ALC268_ACER_ASPIRE_ONE,
Takashi Iwai3866f0b2008-01-15 12:37:42 +0100122 ALC268_DELL,
Mirco Tischlerf12462c2008-02-04 12:33:59 +0100123 ALC268_ZEPTO,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +0100124#ifdef CONFIG_SND_DEBUG
125 ALC268_TEST,
126#endif
Kailang Yanga361d842007-06-05 12:30:55 +0200127 ALC268_AUTO,
128 ALC268_MODEL_LAST /* last tag */
129};
130
Kailang Yangf6a92242007-12-13 16:52:54 +0100131/* ALC269 models */
132enum {
133 ALC269_BASIC,
Kailang Yang60db6b52008-08-26 13:13:00 +0200134 ALC269_QUANTA_FL1,
Kailang Yang84898e82010-02-04 14:16:14 +0100135 ALC269_AMIC,
136 ALC269_DMIC,
137 ALC269VB_AMIC,
138 ALC269VB_DMIC,
Takashi Iwai26f5df22008-11-03 17:39:46 +0100139 ALC269_FUJITSU,
Tony Vroon64154832008-11-06 15:08:49 +0000140 ALC269_LIFEBOOK,
Kailang Yangfe3eb0a2010-08-06 10:02:57 +0200141 ALC271_ACER,
Kailang Yangf6a92242007-12-13 16:52:54 +0100142 ALC269_AUTO,
143 ALC269_MODEL_LAST /* last tag */
144};
145
Kailang Yangdf694da2005-12-05 19:42:22 +0100146/* ALC861 models */
147enum {
148 ALC861_3ST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200149 ALC660_3ST,
Kailang Yangdf694da2005-12-05 19:42:22 +0100150 ALC861_3ST_DIG,
151 ALC861_6ST_DIG,
Takashi Iwai22309c32006-08-09 16:57:28 +0200152 ALC861_UNIWILL_M31,
Tobin Davisa53d1ae2006-10-17 12:00:28 +0200153 ALC861_TOSHIBA,
Mariusz Domanski7cdbff92006-10-23 13:42:56 +0200154 ALC861_ASUS,
Takashi Iwai56bb0ca2006-11-22 11:52:52 +0100155 ALC861_ASUS_LAPTOP,
Kailang Yangdf694da2005-12-05 19:42:22 +0100156 ALC861_AUTO,
157 ALC861_MODEL_LAST,
158};
159
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100160/* ALC861-VD models */
161enum {
162 ALC660VD_3ST,
Mike Crash6963f842007-06-25 12:12:51 +0200163 ALC660VD_3ST_DIG,
Takashi Iwai13c94742008-11-05 08:06:08 +0100164 ALC660VD_ASUS_V1S,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100165 ALC861VD_3ST,
166 ALC861VD_3ST_DIG,
167 ALC861VD_6ST_DIG,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200168 ALC861VD_LENOVO,
Kailang Yang272a5272007-05-14 11:00:38 +0200169 ALC861VD_DALLAS,
Kailang Yangd1a991a2007-08-15 16:21:59 +0200170 ALC861VD_HP,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +0100171 ALC861VD_AUTO,
172 ALC861VD_MODEL_LAST,
173};
174
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200175/* ALC662 models */
176enum {
177 ALC662_3ST_2ch_DIG,
178 ALC662_3ST_6ch_DIG,
179 ALC662_3ST_6ch,
180 ALC662_5ST_DIG,
181 ALC662_LENOVO_101E,
Kailang Yang291702f2007-10-16 14:28:03 +0200182 ALC662_ASUS_EEEPC_P701,
Kailang Yang8c427222008-01-10 13:03:59 +0100183 ALC662_ASUS_EEEPC_EP20,
Kailang Yang6dda9f42008-05-27 12:05:31 +0200184 ALC663_ASUS_M51VA,
185 ALC663_ASUS_G71V,
186 ALC663_ASUS_H13,
187 ALC663_ASUS_G50V,
Kailang Yangf1d4e282008-08-26 14:03:29 +0200188 ALC662_ECS,
189 ALC663_ASUS_MODE1,
190 ALC662_ASUS_MODE2,
191 ALC663_ASUS_MODE3,
192 ALC663_ASUS_MODE4,
193 ALC663_ASUS_MODE5,
194 ALC663_ASUS_MODE6,
Kailang Yangebb83ee2009-12-17 12:23:00 +0100195 ALC663_ASUS_MODE7,
196 ALC663_ASUS_MODE8,
Kailang Yang622e84c2009-04-21 07:39:04 +0200197 ALC272_DELL,
198 ALC272_DELL_ZM1,
Chris Pockelé9541ba12009-05-12 08:08:53 +0200199 ALC272_SAMSUNG_NC10,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200200 ALC662_AUTO,
201 ALC662_MODEL_LAST,
202};
203
Kailang Yangdf694da2005-12-05 19:42:22 +0100204/* ALC882 models */
205enum {
206 ALC882_3ST_DIG,
207 ALC882_6ST_DIG,
Takashi Iwai4b146cb2006-07-28 14:42:36 +0200208 ALC882_ARIMA,
Kailang Yangbdd148a2007-05-08 15:19:08 +0200209 ALC882_W2JC,
Kailang Yang272a5272007-05-14 11:00:38 +0200210 ALC882_TARGA,
211 ALC882_ASUS_A7J,
Takashi Iwai914759b2007-09-06 14:52:04 +0200212 ALC882_ASUS_A7M,
Tobin Davis9102cd12006-12-15 10:02:12 +0100213 ALC885_MACPRO,
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -0800214 ALC885_MBA21,
Takashi Iwai87350ad2007-08-16 18:19:38 +0200215 ALC885_MBP3,
Kacper Szczesniak41d55452009-05-07 12:47:43 +0200216 ALC885_MB5,
Luke Yelaviche458b1f2010-02-12 16:28:29 +1100217 ALC885_MACMINI3,
Nicola Fagnanic54728d2007-07-19 23:28:52 +0200218 ALC885_IMAC24,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -0800219 ALC885_IMAC91,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200220 ALC883_3ST_2ch_DIG,
221 ALC883_3ST_6ch_DIG,
222 ALC883_3ST_6ch,
223 ALC883_6ST_DIG,
Kailang Yangccc656c2006-10-17 12:32:26 +0200224 ALC883_TARGA_DIG,
225 ALC883_TARGA_2ch_DIG,
David Heidelberger64a8be72009-06-08 16:15:18 +0200226 ALC883_TARGA_8ch_DIG,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +0200227 ALC883_ACER,
Tobin Davis2880a862007-08-07 11:50:26 +0200228 ALC883_ACER_ASPIRE,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +0800229 ALC888_ACER_ASPIRE_4930G,
Tony Vroond2fd4b02009-06-21 00:40:10 +0100230 ALC888_ACER_ASPIRE_6530G,
Hector Martin3b315d72009-06-02 10:54:19 +0200231 ALC888_ACER_ASPIRE_8930G,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +0200232 ALC888_ACER_ASPIRE_7730G,
Tobin Davisc07584c2006-10-13 12:32:16 +0200233 ALC883_MEDION,
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +0200234 ALC883_MEDION_WIM2160,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +0100235 ALC883_LAPTOP_EAPD,
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200236 ALC883_LENOVO_101E_2ch,
Kailang Yang272a5272007-05-14 11:00:38 +0200237 ALC883_LENOVO_NB0763,
Kailang Yang189609a2007-08-20 11:31:23 +0200238 ALC888_LENOVO_MS7195_DIG,
Kailang Yange2757d52008-08-26 13:17:46 +0200239 ALC888_LENOVO_SKY,
Kailang Yangea1fb292008-08-26 12:58:38 +0200240 ALC883_HAIER_W66,
Claudio Matsuoka4723c022007-07-13 14:36:19 +0200241 ALC888_3ST_HP,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +0100242 ALC888_6ST_DELL,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +0100243 ALC883_MITAC,
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -0430244 ALC883_CLEVO_M540R,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +0100245 ALC883_CLEVO_M720,
Jiang zhefb97dc62008-03-06 11:07:11 +0100246 ALC883_FUJITSU_PI2515,
Vincent Petryef8ef5f2008-11-23 11:31:41 +0800247 ALC888_FUJITSU_XA3530,
Jiang zhe17bba1b2008-06-04 12:11:07 +0200248 ALC883_3ST_6ch_INTEL,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +0200249 ALC889A_INTEL,
250 ALC889_INTEL,
Kailang Yange2757d52008-08-26 13:17:46 +0200251 ALC888_ASUS_M90V,
252 ALC888_ASUS_EEE1601,
Torben Schulzeb4c41d2009-05-18 15:02:35 +0200253 ALC889A_MB31,
Wu Fengguang3ab90932008-11-17 09:51:09 +0100254 ALC1200_ASUS_P5Q,
Guido Günther3e1647c2009-06-05 00:47:26 +0200255 ALC883_SONY_VAIO_TT,
Takashi Iwai49535502009-06-30 15:28:30 +0200256 ALC882_AUTO,
257 ALC882_MODEL_LAST,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200258};
259
Takashi Iwaid4a86d82010-06-23 17:51:26 +0200260/* ALC680 models */
261enum {
262 ALC680_BASE,
263 ALC680_AUTO,
264 ALC680_MODEL_LAST,
265};
266
Kailang Yangdf694da2005-12-05 19:42:22 +0100267/* for GPIO Poll */
268#define GPIO_MASK 0x03
269
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200270/* extra amp-initialization sequence types */
271enum {
272 ALC_INIT_NONE,
273 ALC_INIT_DEFAULT,
274 ALC_INIT_GPIO1,
275 ALC_INIT_GPIO2,
276 ALC_INIT_GPIO3,
277};
278
Takashi Iwai6c819492009-08-10 18:47:44 +0200279struct alc_mic_route {
280 hda_nid_t pin;
281 unsigned char mux_idx;
282 unsigned char amix_idx;
283};
284
Kailang Yang9ad0e492010-09-14 23:22:00 +0200285struct alc_jack {
286 hda_nid_t nid;
287 int type;
288 struct snd_jack *jack;
289};
290
Takashi Iwai6c819492009-08-10 18:47:44 +0200291#define MUX_IDX_UNDEF ((unsigned char)-1)
292
Kailang Yangda00c242010-03-19 11:23:45 +0100293struct alc_customize_define {
294 unsigned int sku_cfg;
295 unsigned char port_connectivity;
296 unsigned char check_sum;
297 unsigned char customization;
298 unsigned char external_amp;
299 unsigned int enable_pcbeep:1;
300 unsigned int platform_type:1;
301 unsigned int swap:1;
302 unsigned int override:1;
David Henningsson90622912010-10-14 14:50:18 +0200303 unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
Kailang Yangda00c242010-03-19 11:23:45 +0100304};
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306struct alc_spec {
307 /* codec parameterization */
Kailang Yangdf694da2005-12-05 19:42:22 +0100308 struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 unsigned int num_mixers;
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100310 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 struct hda_pcm_stream *stream_analog_playback;
321 struct hda_pcm_stream *stream_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +0100322 struct hda_pcm_stream *stream_analog_alt_playback;
323 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 struct hda_pcm_stream *stream_digital_playback;
327 struct hda_pcm_stream *stream_digital_capture;
328
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;
340 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100341 hda_nid_t *capsrc_nids;
Takashi Iwai16ded522005-06-10 19:58:24 +0200342 hda_nid_t dig_in_nid; /* digital-in NID; optional */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Takashi Iwai840b64c2010-07-13 22:49:01 +0200344 /* capture setup for dynamic dual-adc switch */
345 unsigned int cur_adc_idx;
346 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 Iwai6c819492009-08-10 18:47:44 +0200354 struct alc_mic_route ext_mic;
355 struct alc_mic_route int_mic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100358 const struct hda_channel_mode *channel_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 int num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200360 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200361 int const_channel_count;
362 int ext_channel_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 /* PCM information */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100365 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai41e41f12005-06-08 14:48:49 +0200366
Kailang Yang9ad0e492010-09-14 23:22:00 +0200367 /* jack detection */
368 struct snd_array jacks;
369
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200370 /* dynamic controls, init_verbs and input_mux */
371 struct auto_pin_cfg autocfg;
Kailang Yangda00c242010-03-19 11:23:45 +0100372 struct alc_customize_define cdefine;
Takashi Iwai603c4012008-07-30 15:01:44 +0200373 struct snd_array kctls;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -0200374 struct hda_input_mux private_imux[3];
Takashi Iwai41923e42007-10-22 17:20:10 +0200375 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai49535502009-06-30 15:28:30 +0200376 hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
377 hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
Takashi Iwai834be882006-03-01 14:16:17 +0100378
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100379 /* hooks */
380 void (*init_hook)(struct hda_codec *codec);
381 void (*unsol_event)(struct hda_codec *codec, unsigned int res);
Hector Martinf5de24b2009-12-20 22:51:31 +0100382#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -0500383 void (*power_hook)(struct hda_codec *codec);
Hector Martinf5de24b2009-12-20 22:51:31 +0100384#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100385
Takashi Iwai834be882006-03-01 14:16:17 +0100386 /* for pin sensing */
387 unsigned int sense_updated: 1;
388 unsigned int jack_present: 1;
Takashi Iwaibec15c32008-01-28 18:16:30 +0100389 unsigned int master_sw: 1;
Takashi Iwai6c819492009-08-10 18:47:44 +0200390 unsigned int auto_mic:1;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200391
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100392 /* other flags */
393 unsigned int no_analog :1; /* digital I/O only */
Takashi Iwai840b64c2010-07-13 22:49:01 +0200394 unsigned int dual_adc_switch:1; /* switch ADCs (for ALC275) */
Takashi Iwai4a79ba32009-04-22 16:31:35 +0200395 int init_amp;
Takashi Iwaid433a672010-09-20 15:11:54 +0200396 int codec_variant; /* flag for other variants */
Takashi Iwaie64f14f2009-01-20 18:32:55 +0100397
Takashi Iwai2134ea42008-01-10 16:53:55 +0100398 /* for virtual master */
399 hda_nid_t vmaster_nid;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200400#ifdef CONFIG_SND_HDA_POWER_SAVE
401 struct hda_loopback_check loopback;
402#endif
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200403
404 /* for PLL fix */
405 hda_nid_t pll_nid;
406 unsigned int pll_coef_idx, pll_coef_bit;
Kailang Yangdf694da2005-12-05 19:42:22 +0100407};
408
409/*
410 * configuration template - to be copied to the spec instance
411 */
412struct alc_config_preset {
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200413 struct snd_kcontrol_new *mixers[5]; /* should be identical size
414 * with spec
415 */
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100416 struct snd_kcontrol_new *cap_mixer; /* capture mixer */
Kailang Yangdf694da2005-12-05 19:42:22 +0100417 const struct hda_verb *init_verbs[5];
418 unsigned int num_dacs;
419 hda_nid_t *dac_nids;
420 hda_nid_t dig_out_nid; /* optional */
421 hda_nid_t hp_nid; /* optional */
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800422 hda_nid_t *slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100423 unsigned int num_adc_nids;
424 hda_nid_t *adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100425 hda_nid_t *capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100426 hda_nid_t dig_in_nid;
427 unsigned int num_channel_mode;
428 const struct hda_channel_mode *channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200429 int need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200430 int const_channel_count;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200431 unsigned int num_mux_defs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100432 const struct hda_input_mux *input_mux;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100433 void (*unsol_event)(struct hda_codec *, unsigned int);
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200434 void (*setup)(struct hda_codec *);
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100435 void (*init_hook)(struct hda_codec *);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200436#ifdef CONFIG_SND_HDA_POWER_SAVE
437 struct hda_amp_list *loopbacks;
Daniel T Chenc97259d2009-12-27 18:52:08 -0500438 void (*power_hook)(struct hda_codec *codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +0200439#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440};
441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443/*
444 * input MUX handling
445 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200446static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
447 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
449 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
450 struct alc_spec *spec = codec->spec;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200451 unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
452 if (mux_idx >= spec->num_mux_defs)
453 mux_idx = 0;
Takashi Iwai53111142010-03-08 12:13:07 +0100454 if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
455 mux_idx = 0;
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200456 return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457}
458
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200459static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
460 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
463 struct alc_spec *spec = codec->spec;
464 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
465
466 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
467 return 0;
468}
469
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200470static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
471 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
474 struct alc_spec *spec = codec->spec;
Takashi Iwaicd896c32008-11-18 12:36:33 +0100475 const struct hda_input_mux *imux;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaicd896c32008-11-18 12:36:33 +0100477 unsigned int mux_idx;
Takashi Iwaie1406342008-02-11 18:32:32 +0100478 hda_nid_t nid = spec->capsrc_nids ?
479 spec->capsrc_nids[adc_idx] : spec->adc_nids[adc_idx];
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200480 unsigned int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Takashi Iwaicd896c32008-11-18 12:36:33 +0100482 mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
483 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +0100484 if (!imux->num_items && mux_idx > 0)
485 imux = &spec->input_mux[0];
Takashi Iwaicd896c32008-11-18 12:36:33 +0100486
Takashi Iwaia22d5432009-07-27 12:54:26 +0200487 type = get_wcaps_type(get_wcaps(codec, nid));
Takashi Iwai0169b6b2009-06-22 10:50:19 +0200488 if (type == AC_WID_AUD_MIX) {
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100489 /* Matrix-mixer style (e.g. ALC882) */
490 unsigned int *cur_val = &spec->cur_mux[adc_idx];
491 unsigned int i, idx;
492
493 idx = ucontrol->value.enumerated.item[0];
494 if (idx >= imux->num_items)
495 idx = imux->num_items - 1;
496 if (*cur_val == idx)
497 return 0;
498 for (i = 0; i < imux->num_items; i++) {
499 unsigned int v = (i == idx) ? 0 : HDA_AMP_MUTE;
500 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT,
501 imux->items[i].index,
502 HDA_AMP_MUTE, v);
503 }
504 *cur_val = idx;
505 return 1;
506 } else {
507 /* MUX style (e.g. ALC880) */
Takashi Iwaicd896c32008-11-18 12:36:33 +0100508 return snd_hda_input_mux_put(codec, imux, ucontrol, nid,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +0100509 &spec->cur_mux[adc_idx]);
510 }
511}
Takashi Iwaie9edcee2005-06-13 14:16:38 +0200512
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513/*
514 * channel mode setting
515 */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200516static int alc_ch_mode_info(struct snd_kcontrol *kcontrol,
517 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
519 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
520 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100521 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
522 spec->num_channel_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523}
524
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200525static int alc_ch_mode_get(struct snd_kcontrol *kcontrol,
526 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
528 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
529 struct alc_spec *spec = codec->spec;
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +0100530 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200531 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200532 spec->ext_channel_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533}
534
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200535static int alc_ch_mode_put(struct snd_kcontrol *kcontrol,
536 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537{
538 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
539 struct alc_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200540 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
541 spec->num_channel_mode,
Hector Martin3b315d72009-06-02 10:54:19 +0200542 &spec->ext_channel_count);
543 if (err >= 0 && !spec->const_channel_count) {
544 spec->multiout.max_channels = spec->ext_channel_count;
545 if (spec->need_dac_fix)
546 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
547 }
Takashi Iwai4e195a72006-07-28 14:47:34 +0200548 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551/*
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100552 * Control the mode of pin widget settings via the mixer. "pc" is used
Kailang Yangea1fb292008-08-26 12:58:38 +0200553 * instead of "%" to avoid consequences of accidently treating the % as
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100554 * being part of a format specifier. Maximum allowed length of a value is
555 * 63 characters plus NULL terminator.
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100556 *
557 * Note: some retasking pin complexes seem to ignore requests for input
558 * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
559 * are requested. Therefore order this list so that this behaviour will not
560 * cause problems when mixer clients move through the enum sequentially.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200561 * NIDs 0x0f and 0x10 have been observed to have this behaviour as of
562 * March 2006.
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200563 */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100564static char *alc_pin_mode_names[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100565 "Mic 50pc bias", "Mic 80pc bias",
566 "Line in", "Line out", "Headphone out",
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100567};
568static unsigned char alc_pin_mode_values[] = {
Jonathan Woithe7cf51e42006-02-09 12:01:26 +0100569 PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100570};
571/* The control can present all 5 options, or it can limit the options based
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200572 * in the pin being assumed to be exclusively an input or an output pin. In
573 * addition, "input" pins may or may not process the mic bias option
574 * depending on actual widget capability (NIDs 0x0f and 0x10 don't seem to
575 * accept requests for bias as of chip versions up to March 2006) and/or
576 * wiring in the computer.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100577 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200578#define ALC_PIN_DIR_IN 0x00
579#define ALC_PIN_DIR_OUT 0x01
580#define ALC_PIN_DIR_INOUT 0x02
581#define ALC_PIN_DIR_IN_NOMICBIAS 0x03
582#define ALC_PIN_DIR_INOUT_NOMICBIAS 0x04
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100583
Kailang Yangea1fb292008-08-26 12:58:38 +0200584/* Info about the pin modes supported by the different pin direction modes.
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100585 * For each direction the minimum and maximum values are given.
586 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200587static signed char alc_pin_mode_dir_info[5][2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100588 { 0, 2 }, /* ALC_PIN_DIR_IN */
589 { 3, 4 }, /* ALC_PIN_DIR_OUT */
590 { 0, 4 }, /* ALC_PIN_DIR_INOUT */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200591 { 2, 2 }, /* ALC_PIN_DIR_IN_NOMICBIAS */
592 { 2, 4 }, /* ALC_PIN_DIR_INOUT_NOMICBIAS */
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100593};
594#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
595#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
596#define alc_pin_mode_n_items(_dir) \
597 (alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
598
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200599static int alc_pin_mode_info(struct snd_kcontrol *kcontrol,
600 struct snd_ctl_elem_info *uinfo)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200601{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100602 unsigned int item_num = uinfo->value.enumerated.item;
603 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
604
605 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200606 uinfo->count = 1;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100607 uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
608
609 if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
610 item_num = alc_pin_mode_min(dir);
611 strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200612 return 0;
613}
614
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200615static int alc_pin_mode_get(struct snd_kcontrol *kcontrol,
616 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200617{
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100618 unsigned int i;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200619 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
620 hda_nid_t nid = kcontrol->private_value & 0xffff;
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100621 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200622 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200623 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
624 AC_VERB_GET_PIN_WIDGET_CONTROL,
625 0x00);
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200626
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100627 /* Find enumerated value for current pinctl setting */
628 i = alc_pin_mode_min(dir);
Roel Kluin4b35d2c2009-08-02 13:30:45 +0200629 while (i <= alc_pin_mode_max(dir) && alc_pin_mode_values[i] != pinctl)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100630 i++;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200631 *valp = i <= alc_pin_mode_max(dir) ? i: alc_pin_mode_min(dir);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100632 return 0;
633}
634
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200635static int alc_pin_mode_put(struct snd_kcontrol *kcontrol,
636 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100637{
638 signed int change;
639 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
640 hda_nid_t nid = kcontrol->private_value & 0xffff;
641 unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
642 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200643 unsigned int pinctl = snd_hda_codec_read(codec, nid, 0,
644 AC_VERB_GET_PIN_WIDGET_CONTROL,
645 0x00);
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100646
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200647 if (val < alc_pin_mode_min(dir) || val > alc_pin_mode_max(dir))
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100648 val = alc_pin_mode_min(dir);
649
650 change = pinctl != alc_pin_mode_values[val];
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100651 if (change) {
652 /* Set pin mode to that requested */
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200653 snd_hda_codec_write_cache(codec, nid, 0,
654 AC_VERB_SET_PIN_WIDGET_CONTROL,
655 alc_pin_mode_values[val]);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100656
Kailang Yangea1fb292008-08-26 12:58:38 +0200657 /* Also enable the retasking pin's input/output as required
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100658 * for the requested pin mode. Enum values of 2 or less are
659 * input modes.
660 *
661 * Dynamically switching the input/output buffers probably
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200662 * reduces noise slightly (particularly on input) so we'll
663 * do it. However, having both input and output buffers
664 * enabled simultaneously doesn't seem to be problematic if
665 * this turns out to be necessary in the future.
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100666 */
667 if (val <= 2) {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200668 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
669 HDA_AMP_MUTE, HDA_AMP_MUTE);
670 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
671 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100672 } else {
Takashi Iwai47fd8302007-08-10 17:11:07 +0200673 snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
674 HDA_AMP_MUTE, HDA_AMP_MUTE);
675 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
676 HDA_AMP_MUTE, 0);
Jonathan Woithecdcd9262006-02-28 11:36:42 +0100677 }
678 }
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200679 return change;
680}
681
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100682#define ALC_PIN_MODE(xname, nid, dir) \
Jonathan Woithea9430dd2005-09-16 19:12:48 +0200683 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100684 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe4c5186e2006-02-09 11:53:48 +0100685 .info = alc_pin_mode_info, \
686 .get = alc_pin_mode_get, \
687 .put = alc_pin_mode_put, \
688 .private_value = nid | (dir<<16) }
Kailang Yangdf694da2005-12-05 19:42:22 +0100689
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100690/* A switch control for ALC260 GPIO pins. Multiple GPIOs can be ganged
691 * together using a mask with more than one bit set. This control is
692 * currently used only by the ALC260 test model. At this stage they are not
693 * needed for any "production" models.
694 */
695#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200696#define alc_gpio_data_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200697
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200698static int alc_gpio_data_get(struct snd_kcontrol *kcontrol,
699 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100700{
701 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
702 hda_nid_t nid = kcontrol->private_value & 0xffff;
703 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
704 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200705 unsigned int val = snd_hda_codec_read(codec, nid, 0,
706 AC_VERB_GET_GPIO_DATA, 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100707
708 *valp = (val & mask) != 0;
709 return 0;
710}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200711static int alc_gpio_data_put(struct snd_kcontrol *kcontrol,
712 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100713{
714 signed int change;
715 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
716 hda_nid_t nid = kcontrol->private_value & 0xffff;
717 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
718 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200719 unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0,
720 AC_VERB_GET_GPIO_DATA,
721 0x00);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100722
723 /* Set/unset the masked GPIO bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200724 change = (val == 0 ? 0 : mask) != (gpio_data & mask);
725 if (val == 0)
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100726 gpio_data &= ~mask;
727 else
728 gpio_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200729 snd_hda_codec_write_cache(codec, nid, 0,
730 AC_VERB_SET_GPIO_DATA, gpio_data);
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100731
732 return change;
733}
734#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
735 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100736 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe5c8f8582006-02-28 11:43:27 +0100737 .info = alc_gpio_data_info, \
738 .get = alc_gpio_data_get, \
739 .put = alc_gpio_data_put, \
740 .private_value = nid | (mask<<16) }
741#endif /* CONFIG_SND_DEBUG */
742
Jonathan Woithe92621f12006-02-28 11:47:47 +0100743/* A switch control to allow the enabling of the digital IO pins on the
744 * ALC260. This is incredibly simplistic; the intention of this control is
745 * to provide something in the test model allowing digital outputs to be
746 * identified if present. If models are found which can utilise these
747 * outputs a more complete mixer control can be devised for those models if
748 * necessary.
749 */
750#ifdef CONFIG_SND_DEBUG
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200751#define alc_spdif_ctrl_info snd_ctl_boolean_mono_info
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200752
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200753static int alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol,
754 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100755{
756 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
757 hda_nid_t nid = kcontrol->private_value & 0xffff;
758 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
759 long *valp = ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200760 unsigned int val = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100761 AC_VERB_GET_DIGI_CONVERT_1, 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100762
763 *valp = (val & mask) != 0;
764 return 0;
765}
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200766static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol,
767 struct snd_ctl_elem_value *ucontrol)
Jonathan Woithe92621f12006-02-28 11:47:47 +0100768{
769 signed int change;
770 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
771 hda_nid_t nid = kcontrol->private_value & 0xffff;
772 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
773 long val = *ucontrol->value.integer.value;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200774 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
Andrew Paprocki3982d172007-12-19 12:13:44 +0100775 AC_VERB_GET_DIGI_CONVERT_1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200776 0x00);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100777
778 /* Set/unset the masked control bit(s) as needed */
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200779 change = (val == 0 ? 0 : mask) != (ctrl_data & mask);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100780 if (val==0)
781 ctrl_data &= ~mask;
782 else
783 ctrl_data |= mask;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200784 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
785 ctrl_data);
Jonathan Woithe92621f12006-02-28 11:47:47 +0100786
787 return change;
788}
789#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
790 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100791 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithe92621f12006-02-28 11:47:47 +0100792 .info = alc_spdif_ctrl_info, \
793 .get = alc_spdif_ctrl_get, \
794 .put = alc_spdif_ctrl_put, \
795 .private_value = nid | (mask<<16) }
796#endif /* CONFIG_SND_DEBUG */
797
Jonathan Woithef8225f62008-01-08 12:16:54 +0100798/* A switch control to allow the enabling EAPD digital outputs on the ALC26x.
799 * Again, this is only used in the ALC26x test models to help identify when
800 * the EAPD line must be asserted for features to work.
801 */
802#ifdef CONFIG_SND_DEBUG
803#define alc_eapd_ctrl_info snd_ctl_boolean_mono_info
804
805static int alc_eapd_ctrl_get(struct snd_kcontrol *kcontrol,
806 struct snd_ctl_elem_value *ucontrol)
807{
808 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
809 hda_nid_t nid = kcontrol->private_value & 0xffff;
810 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
811 long *valp = ucontrol->value.integer.value;
812 unsigned int val = snd_hda_codec_read(codec, nid, 0,
813 AC_VERB_GET_EAPD_BTLENABLE, 0x00);
814
815 *valp = (val & mask) != 0;
816 return 0;
817}
818
819static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol,
820 struct snd_ctl_elem_value *ucontrol)
821{
822 int change;
823 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
824 hda_nid_t nid = kcontrol->private_value & 0xffff;
825 unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
826 long val = *ucontrol->value.integer.value;
827 unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0,
828 AC_VERB_GET_EAPD_BTLENABLE,
829 0x00);
830
831 /* Set/unset the masked control bit(s) as needed */
832 change = (!val ? 0 : mask) != (ctrl_data & mask);
833 if (!val)
834 ctrl_data &= ~mask;
835 else
836 ctrl_data |= mask;
837 snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
838 ctrl_data);
839
840 return change;
841}
842
843#define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \
844 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100845 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Jonathan Woithef8225f62008-01-08 12:16:54 +0100846 .info = alc_eapd_ctrl_info, \
847 .get = alc_eapd_ctrl_get, \
848 .put = alc_eapd_ctrl_put, \
849 .private_value = nid | (mask<<16) }
850#endif /* CONFIG_SND_DEBUG */
851
Kailang Yangdf694da2005-12-05 19:42:22 +0100852/*
Takashi Iwai23f0c042009-02-26 13:03:58 +0100853 * set up the input pin config (depending on the given auto-pin type)
854 */
855static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
856 int auto_pin_type)
857{
858 unsigned int val = PIN_IN;
859
Takashi Iwai86e29592010-09-09 14:50:17 +0200860 if (auto_pin_type == AUTO_PIN_MIC) {
Takashi Iwai23f0c042009-02-26 13:03:58 +0100861 unsigned int pincap;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200862 unsigned int oldval;
863 oldval = snd_hda_codec_read(codec, nid, 0,
864 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
Takashi Iwai1327a322009-03-23 13:07:47 +0100865 pincap = snd_hda_query_pin_caps(codec, nid);
Takashi Iwai23f0c042009-02-26 13:03:58 +0100866 pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
Takashi Iwai954a29c2010-07-30 10:55:44 +0200867 /* if the default pin setup is vref50, we give it priority */
868 if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
Takashi Iwai23f0c042009-02-26 13:03:58 +0100869 val = PIN_VREF80;
Takashi Iwai461c6c32009-05-25 08:06:02 +0200870 else if (pincap & AC_PINCAP_VREF_50)
871 val = PIN_VREF50;
872 else if (pincap & AC_PINCAP_VREF_100)
873 val = PIN_VREF100;
874 else if (pincap & AC_PINCAP_VREF_GRD)
875 val = PIN_VREFGRD;
Takashi Iwai23f0c042009-02-26 13:03:58 +0100876 }
877 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
878}
879
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200880static void alc_fixup_autocfg_pin_nums(struct hda_codec *codec)
881{
882 struct alc_spec *spec = codec->spec;
883 struct auto_pin_cfg *cfg = &spec->autocfg;
884
885 if (!cfg->line_outs) {
886 while (cfg->line_outs < AUTO_CFG_MAX_OUTS &&
887 cfg->line_out_pins[cfg->line_outs])
888 cfg->line_outs++;
889 }
890 if (!cfg->speaker_outs) {
891 while (cfg->speaker_outs < AUTO_CFG_MAX_OUTS &&
892 cfg->speaker_pins[cfg->speaker_outs])
893 cfg->speaker_outs++;
894 }
895 if (!cfg->hp_outs) {
896 while (cfg->hp_outs < AUTO_CFG_MAX_OUTS &&
897 cfg->hp_pins[cfg->hp_outs])
898 cfg->hp_outs++;
899 }
900}
901
Takashi Iwai23f0c042009-02-26 13:03:58 +0100902/*
Takashi Iwaid88897e2008-10-31 15:01:37 +0100903 */
904static void add_mixer(struct alc_spec *spec, struct snd_kcontrol_new *mix)
905{
906 if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
907 return;
908 spec->mixers[spec->num_mixers++] = mix;
909}
910
911static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
912{
913 if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
914 return;
915 spec->init_verbs[spec->num_init_verbs++] = verb;
916}
917
918/*
Kailang Yangdf694da2005-12-05 19:42:22 +0100919 * set up from the preset table
920 */
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200921static void setup_preset(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200922 const struct alc_config_preset *preset)
Kailang Yangdf694da2005-12-05 19:42:22 +0100923{
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200924 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +0100925 int i;
926
927 for (i = 0; i < ARRAY_SIZE(preset->mixers) && preset->mixers[i]; i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100928 add_mixer(spec, preset->mixers[i]);
Takashi Iwaif9e336f2008-10-31 16:37:07 +0100929 spec->cap_mixer = preset->cap_mixer;
Takashi Iwai9c7f8522006-06-28 15:08:22 +0200930 for (i = 0; i < ARRAY_SIZE(preset->init_verbs) && preset->init_verbs[i];
931 i++)
Takashi Iwaid88897e2008-10-31 15:01:37 +0100932 add_verb(spec, preset->init_verbs[i]);
Kailang Yangea1fb292008-08-26 12:58:38 +0200933
Kailang Yangdf694da2005-12-05 19:42:22 +0100934 spec->channel_mode = preset->channel_mode;
935 spec->num_channel_mode = preset->num_channel_mode;
Takashi Iwai4e195a72006-07-28 14:47:34 +0200936 spec->need_dac_fix = preset->need_dac_fix;
Hector Martin3b315d72009-06-02 10:54:19 +0200937 spec->const_channel_count = preset->const_channel_count;
Kailang Yangdf694da2005-12-05 19:42:22 +0100938
Hector Martin3b315d72009-06-02 10:54:19 +0200939 if (preset->const_channel_count)
940 spec->multiout.max_channels = preset->const_channel_count;
941 else
942 spec->multiout.max_channels = spec->channel_mode[0].channels;
943 spec->ext_channel_count = spec->channel_mode[0].channels;
Kailang Yangdf694da2005-12-05 19:42:22 +0100944
945 spec->multiout.num_dacs = preset->num_dacs;
946 spec->multiout.dac_nids = preset->dac_nids;
947 spec->multiout.dig_out_nid = preset->dig_out_nid;
Wu Fengguangb25c9da2009-02-06 15:02:27 +0800948 spec->multiout.slave_dig_outs = preset->slave_dig_outs;
Kailang Yangdf694da2005-12-05 19:42:22 +0100949 spec->multiout.hp_nid = preset->hp_nid;
Kailang Yangea1fb292008-08-26 12:58:38 +0200950
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200951 spec->num_mux_defs = preset->num_mux_defs;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +0200952 if (!spec->num_mux_defs)
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +0200953 spec->num_mux_defs = 1;
Kailang Yangdf694da2005-12-05 19:42:22 +0100954 spec->input_mux = preset->input_mux;
955
956 spec->num_adc_nids = preset->num_adc_nids;
957 spec->adc_nids = preset->adc_nids;
Takashi Iwaie1406342008-02-11 18:32:32 +0100958 spec->capsrc_nids = preset->capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +0100959 spec->dig_in_nid = preset->dig_in_nid;
Takashi Iwaiae6b8132006-03-03 16:47:17 +0100960
961 spec->unsol_event = preset->unsol_event;
962 spec->init_hook = preset->init_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200963#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +0100964 spec->power_hook = preset->power_hook;
Takashi Iwaicb53c622007-08-10 17:21:45 +0200965 spec->loopback.amplist = preset->loopbacks;
966#endif
Takashi Iwaie9c364c2009-08-11 17:16:13 +0200967
968 if (preset->setup)
969 preset->setup(codec);
Takashi Iwaif6837bb2010-09-20 14:56:32 +0200970
971 alc_fixup_autocfg_pin_nums(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +0100972}
973
Kailang Yangbc9f98a2007-04-12 13:06:07 +0200974/* Enable GPIO mask and set output */
975static struct hda_verb alc_gpio1_init_verbs[] = {
976 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
977 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
978 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
979 { }
980};
981
982static struct hda_verb alc_gpio2_init_verbs[] = {
983 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
984 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
985 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
986 { }
987};
988
Kailang Yangbdd148a2007-05-08 15:19:08 +0200989static struct hda_verb alc_gpio3_init_verbs[] = {
990 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
991 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
992 {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
993 { }
994};
995
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +0200996/*
997 * Fix hardware PLL issue
998 * On some codecs, the analog PLL gating control must be off while
999 * the default value is 1.
1000 */
1001static void alc_fix_pll(struct hda_codec *codec)
1002{
1003 struct alc_spec *spec = codec->spec;
1004 unsigned int val;
1005
1006 if (!spec->pll_nid)
1007 return;
1008 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1009 spec->pll_coef_idx);
1010 val = snd_hda_codec_read(codec, spec->pll_nid, 0,
1011 AC_VERB_GET_PROC_COEF, 0);
1012 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
1013 spec->pll_coef_idx);
1014 snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
1015 val & ~(1 << spec->pll_coef_bit));
1016}
1017
1018static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
1019 unsigned int coef_idx, unsigned int coef_bit)
1020{
1021 struct alc_spec *spec = codec->spec;
1022 spec->pll_nid = nid;
1023 spec->pll_coef_idx = coef_idx;
1024 spec->pll_coef_bit = coef_bit;
1025 alc_fix_pll(codec);
1026}
1027
Kailang Yang9ad0e492010-09-14 23:22:00 +02001028#ifdef CONFIG_SND_HDA_INPUT_JACK
1029static void alc_free_jack_priv(struct snd_jack *jack)
1030{
1031 struct alc_jack *jacks = jack->private_data;
1032 jacks->nid = 0;
1033 jacks->jack = NULL;
1034}
1035
1036static int alc_add_jack(struct hda_codec *codec,
1037 hda_nid_t nid, int type)
1038{
1039 struct alc_spec *spec;
1040 struct alc_jack *jack;
1041 const char *name;
1042 int err;
1043
1044 spec = codec->spec;
1045 snd_array_init(&spec->jacks, sizeof(*jack), 32);
1046 jack = snd_array_new(&spec->jacks);
1047 if (!jack)
1048 return -ENOMEM;
1049
1050 jack->nid = nid;
1051 jack->type = type;
1052 name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;
1053
1054 err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
1055 if (err < 0)
1056 return err;
1057 jack->jack->private_data = jack;
1058 jack->jack->private_free = alc_free_jack_priv;
1059 return 0;
1060}
1061
1062static void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
1063{
1064 struct alc_spec *spec = codec->spec;
1065 struct alc_jack *jacks = spec->jacks.list;
1066
1067 if (jacks) {
1068 int i;
1069 for (i = 0; i < spec->jacks.used; i++) {
1070 if (jacks->nid == nid) {
1071 unsigned int present;
1072 present = snd_hda_jack_detect(codec, nid);
1073
1074 present = (present) ? jacks->type : 0;
1075
1076 snd_jack_report(jacks->jack, present);
1077 }
1078 jacks++;
1079 }
1080 }
1081}
1082
1083static int alc_init_jacks(struct hda_codec *codec)
1084{
1085 struct alc_spec *spec = codec->spec;
1086 int err;
1087 unsigned int hp_nid = spec->autocfg.hp_pins[0];
1088 unsigned int mic_nid = spec->ext_mic.pin;
1089
Takashi Iwai265a0242010-09-21 11:26:21 +02001090 if (hp_nid) {
1091 err = alc_add_jack(codec, hp_nid, SND_JACK_HEADPHONE);
1092 if (err < 0)
1093 return err;
1094 alc_report_jack(codec, hp_nid);
1095 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001096
Takashi Iwai265a0242010-09-21 11:26:21 +02001097 if (mic_nid) {
1098 err = alc_add_jack(codec, mic_nid, SND_JACK_MICROPHONE);
1099 if (err < 0)
1100 return err;
1101 alc_report_jack(codec, mic_nid);
1102 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001103
1104 return 0;
1105}
1106#else
1107static inline void alc_report_jack(struct hda_codec *codec, hda_nid_t nid)
1108{
1109}
1110
1111static inline int alc_init_jacks(struct hda_codec *codec)
1112{
1113 return 0;
1114}
1115#endif
1116
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001117static void alc_automute_speaker(struct hda_codec *codec, int pinctl)
Kailang Yangc9b58002007-10-16 14:30:01 +02001118{
1119 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001120 unsigned int mute;
1121 hda_nid_t nid;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001122 int i;
Kailang Yangc9b58002007-10-16 14:30:01 +02001123
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001124 spec->jack_present = 0;
1125 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
1126 nid = spec->autocfg.hp_pins[i];
1127 if (!nid)
1128 break;
1129 if (snd_hda_jack_detect(codec, nid)) {
1130 spec->jack_present = 1;
1131 break;
1132 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001133 alc_report_jack(codec, spec->autocfg.hp_pins[i]);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001134 }
1135
1136 mute = spec->jack_present ? HDA_AMP_MUTE : 0;
1137 /* Toggle internal speakers muting */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001138 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
1139 nid = spec->autocfg.speaker_pins[i];
1140 if (!nid)
1141 break;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001142 if (pinctl) {
1143 snd_hda_codec_write(codec, nid, 0,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001144 AC_VERB_SET_PIN_WIDGET_CONTROL,
1145 spec->jack_present ? 0 : PIN_OUT);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001146 } else {
1147 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
1148 HDA_AMP_MUTE, mute);
1149 }
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001150 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001151}
1152
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001153static void alc_automute_pin(struct hda_codec *codec)
1154{
1155 alc_automute_speaker(codec, 1);
1156}
1157
Takashi Iwai6c819492009-08-10 18:47:44 +02001158static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
1159 hda_nid_t nid)
1160{
1161 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
1162 int i, nums;
1163
1164 nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
1165 for (i = 0; i < nums; i++)
1166 if (conn[i] == nid)
1167 return i;
1168 return -1;
1169}
1170
Takashi Iwai840b64c2010-07-13 22:49:01 +02001171/* switch the current ADC according to the jack state */
1172static void alc_dual_mic_adc_auto_switch(struct hda_codec *codec)
1173{
1174 struct alc_spec *spec = codec->spec;
1175 unsigned int present;
1176 hda_nid_t new_adc;
1177
1178 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
1179 if (present)
1180 spec->cur_adc_idx = 1;
1181 else
1182 spec->cur_adc_idx = 0;
1183 new_adc = spec->adc_nids[spec->cur_adc_idx];
1184 if (spec->cur_adc && spec->cur_adc != new_adc) {
1185 /* stream is running, let's swap the current ADC */
Takashi Iwaif0cea792010-08-13 11:56:53 +02001186 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
Takashi Iwai840b64c2010-07-13 22:49:01 +02001187 spec->cur_adc = new_adc;
1188 snd_hda_codec_setup_stream(codec, new_adc,
1189 spec->cur_adc_stream_tag, 0,
1190 spec->cur_adc_format);
1191 }
1192}
1193
Kailang Yang7fb0d782008-10-15 11:12:35 +02001194static void alc_mic_automute(struct hda_codec *codec)
1195{
1196 struct alc_spec *spec = codec->spec;
Takashi Iwai6c819492009-08-10 18:47:44 +02001197 struct alc_mic_route *dead, *alive;
1198 unsigned int present, type;
1199 hda_nid_t cap_nid;
Kailang Yang7fb0d782008-10-15 11:12:35 +02001200
Takashi Iwaib59bdf32009-08-11 09:47:30 +02001201 if (!spec->auto_mic)
1202 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001203 if (!spec->int_mic.pin || !spec->ext_mic.pin)
1204 return;
1205 if (snd_BUG_ON(!spec->adc_nids))
1206 return;
1207
Takashi Iwai840b64c2010-07-13 22:49:01 +02001208 if (spec->dual_adc_switch) {
1209 alc_dual_mic_adc_auto_switch(codec);
1210 return;
1211 }
1212
Takashi Iwai6c819492009-08-10 18:47:44 +02001213 cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0];
1214
Wu Fengguang864f92b2009-11-18 12:38:02 +08001215 present = snd_hda_jack_detect(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001216 if (present) {
1217 alive = &spec->ext_mic;
1218 dead = &spec->int_mic;
1219 } else {
1220 alive = &spec->int_mic;
1221 dead = &spec->ext_mic;
1222 }
1223
Takashi Iwai6c819492009-08-10 18:47:44 +02001224 type = get_wcaps_type(get_wcaps(codec, cap_nid));
1225 if (type == AC_WID_AUD_MIX) {
1226 /* Matrix-mixer style (e.g. ALC882) */
1227 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1228 alive->mux_idx,
1229 HDA_AMP_MUTE, 0);
1230 snd_hda_codec_amp_stereo(codec, cap_nid, HDA_INPUT,
1231 dead->mux_idx,
1232 HDA_AMP_MUTE, HDA_AMP_MUTE);
1233 } else {
1234 /* MUX style (e.g. ALC880) */
1235 snd_hda_codec_write_cache(codec, cap_nid, 0,
1236 AC_VERB_SET_CONNECT_SEL,
1237 alive->mux_idx);
1238 }
Kailang Yang9ad0e492010-09-14 23:22:00 +02001239 alc_report_jack(codec, spec->ext_mic.pin);
Takashi Iwai6c819492009-08-10 18:47:44 +02001240
1241 /* FIXME: analog mixer */
Kailang Yang7fb0d782008-10-15 11:12:35 +02001242}
1243
Kailang Yangc9b58002007-10-16 14:30:01 +02001244/* unsolicited event for HP jack sensing */
1245static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
1246{
1247 if (codec->vendor_id == 0x10ec0880)
1248 res >>= 28;
1249 else
1250 res >>= 26;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001251 switch (res) {
1252 case ALC880_HP_EVENT:
1253 alc_automute_pin(codec);
1254 break;
1255 case ALC880_MIC_EVENT:
Kailang Yang7fb0d782008-10-15 11:12:35 +02001256 alc_mic_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001257 break;
1258 }
Kailang Yang7fb0d782008-10-15 11:12:35 +02001259}
1260
1261static void alc_inithook(struct hda_codec *codec)
1262{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001263 alc_automute_pin(codec);
Kailang Yang7fb0d782008-10-15 11:12:35 +02001264 alc_mic_automute(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001265}
1266
Kailang Yangf9423e72008-05-27 12:32:25 +02001267/* additional initialization for ALC888 variants */
1268static void alc888_coef_init(struct hda_codec *codec)
1269{
1270 unsigned int tmp;
1271
1272 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
1273 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1274 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
Takashi Iwai37db6232009-03-05 09:40:16 +01001275 if ((tmp & 0xf0) == 0x20)
Kailang Yangf9423e72008-05-27 12:32:25 +02001276 /* alc888S-VC */
1277 snd_hda_codec_read(codec, 0x20, 0,
1278 AC_VERB_SET_PROC_COEF, 0x830);
1279 else
1280 /* alc888-VB */
1281 snd_hda_codec_read(codec, 0x20, 0,
1282 AC_VERB_SET_PROC_COEF, 0x3030);
1283}
1284
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001285static void alc889_coef_init(struct hda_codec *codec)
1286{
1287 unsigned int tmp;
1288
1289 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1290 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
1291 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
1292 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
1293}
1294
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001295/* turn on/off EAPD control (only if available) */
1296static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
1297{
1298 if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
1299 return;
1300 if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
1301 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
1302 on ? 2 : 0);
1303}
1304
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001305static void alc_auto_init_amp(struct hda_codec *codec, int type)
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001306{
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001307 unsigned int tmp;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001308
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001309 switch (type) {
1310 case ALC_INIT_GPIO1:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001311 snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
1312 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001313 case ALC_INIT_GPIO2:
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001314 snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
1315 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001316 case ALC_INIT_GPIO3:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001317 snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
1318 break;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001319 case ALC_INIT_DEFAULT:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001320 switch (codec->vendor_id) {
Kailang Yangc9b58002007-10-16 14:30:01 +02001321 case 0x10ec0260:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001322 set_eapd(codec, 0x0f, 1);
1323 set_eapd(codec, 0x10, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001324 break;
1325 case 0x10ec0262:
Kailang Yangbdd148a2007-05-08 15:19:08 +02001326 case 0x10ec0267:
1327 case 0x10ec0268:
Kailang Yangc9b58002007-10-16 14:30:01 +02001328 case 0x10ec0269:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001329 case 0x10ec0270:
Takashi Iwaic6e8f2d2009-02-06 12:45:52 +01001330 case 0x10ec0272:
Kailang Yangf9423e72008-05-27 12:32:25 +02001331 case 0x10ec0660:
1332 case 0x10ec0662:
1333 case 0x10ec0663:
Kailang Yangc9b58002007-10-16 14:30:01 +02001334 case 0x10ec0862:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001335 case 0x10ec0889:
Takashi Iwai3fb4a502010-01-19 15:46:37 +01001336 set_eapd(codec, 0x14, 1);
1337 set_eapd(codec, 0x15, 1);
Kailang Yangc9b58002007-10-16 14:30:01 +02001338 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +02001339 }
Kailang Yangc9b58002007-10-16 14:30:01 +02001340 switch (codec->vendor_id) {
1341 case 0x10ec0260:
1342 snd_hda_codec_write(codec, 0x1a, 0,
1343 AC_VERB_SET_COEF_INDEX, 7);
1344 tmp = snd_hda_codec_read(codec, 0x1a, 0,
1345 AC_VERB_GET_PROC_COEF, 0);
1346 snd_hda_codec_write(codec, 0x1a, 0,
1347 AC_VERB_SET_COEF_INDEX, 7);
1348 snd_hda_codec_write(codec, 0x1a, 0,
1349 AC_VERB_SET_PROC_COEF,
1350 tmp | 0x2010);
1351 break;
1352 case 0x10ec0262:
1353 case 0x10ec0880:
1354 case 0x10ec0882:
1355 case 0x10ec0883:
1356 case 0x10ec0885:
Takashi Iwai4a5a4c52009-02-06 12:46:59 +01001357 case 0x10ec0887:
Takashi Iwai20a3a052008-05-23 17:52:53 +02001358 case 0x10ec0889:
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02001359 alc889_coef_init(codec);
Kailang Yangc9b58002007-10-16 14:30:01 +02001360 break;
Kailang Yangf9423e72008-05-27 12:32:25 +02001361 case 0x10ec0888:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001362 alc888_coef_init(codec);
Kailang Yangf9423e72008-05-27 12:32:25 +02001363 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001364#if 0 /* XXX: This may cause the silent output on speaker on some machines */
Kailang Yangc9b58002007-10-16 14:30:01 +02001365 case 0x10ec0267:
1366 case 0x10ec0268:
1367 snd_hda_codec_write(codec, 0x20, 0,
1368 AC_VERB_SET_COEF_INDEX, 7);
1369 tmp = snd_hda_codec_read(codec, 0x20, 0,
1370 AC_VERB_GET_PROC_COEF, 0);
1371 snd_hda_codec_write(codec, 0x20, 0,
Kailang Yangea1fb292008-08-26 12:58:38 +02001372 AC_VERB_SET_COEF_INDEX, 7);
Kailang Yangc9b58002007-10-16 14:30:01 +02001373 snd_hda_codec_write(codec, 0x20, 0,
1374 AC_VERB_SET_PROC_COEF,
1375 tmp | 0x3000);
1376 break;
Takashi Iwai0aea7782010-01-25 15:44:11 +01001377#endif /* XXX */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001378 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001379 break;
1380 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001381}
Kailang Yangea1fb292008-08-26 12:58:38 +02001382
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001383static void alc_init_auto_hp(struct hda_codec *codec)
1384{
1385 struct alc_spec *spec = codec->spec;
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001386 struct auto_pin_cfg *cfg = &spec->autocfg;
1387 int i;
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001388
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001389 if (!cfg->hp_pins[0]) {
1390 if (cfg->line_out_type != AUTO_PIN_HP_OUT)
Kailang Yangc9b58002007-10-16 14:30:01 +02001391 return;
1392 }
1393
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001394 if (!cfg->speaker_pins[0]) {
1395 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
1396 return;
1397 memcpy(cfg->speaker_pins, cfg->line_out_pins,
1398 sizeof(cfg->speaker_pins));
1399 cfg->speaker_outs = cfg->line_outs;
1400 }
1401
1402 if (!cfg->hp_pins[0]) {
1403 memcpy(cfg->hp_pins, cfg->line_out_pins,
1404 sizeof(cfg->hp_pins));
1405 cfg->hp_outs = cfg->line_outs;
1406 }
1407
1408 for (i = 0; i < cfg->hp_outs; i++) {
1409 snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n",
1410 cfg->hp_pins[i]);
1411 snd_hda_codec_write_cache(codec, cfg->hp_pins[i], 0,
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001412 AC_VERB_SET_UNSOLICITED_ENABLE,
1413 AC_USRSP_EN | ALC880_HP_EVENT);
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001414 }
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001415 spec->unsol_event = alc_sku_unsol_event;
1416}
1417
Takashi Iwai6c819492009-08-10 18:47:44 +02001418static void alc_init_auto_mic(struct hda_codec *codec)
1419{
1420 struct alc_spec *spec = codec->spec;
1421 struct auto_pin_cfg *cfg = &spec->autocfg;
1422 hda_nid_t fixed, ext;
1423 int i;
1424
1425 /* there must be only two mic inputs exclusively */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001426 for (i = 0; i < cfg->num_inputs; i++)
Takashi Iwai86e29592010-09-09 14:50:17 +02001427 if (cfg->inputs[i].type >= AUTO_PIN_LINE_IN)
Takashi Iwai6c819492009-08-10 18:47:44 +02001428 return;
1429
1430 fixed = ext = 0;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02001431 for (i = 0; i < cfg->num_inputs; i++) {
1432 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai6c819492009-08-10 18:47:44 +02001433 unsigned int defcfg;
Takashi Iwai6c819492009-08-10 18:47:44 +02001434 defcfg = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001435 switch (snd_hda_get_input_pin_attr(defcfg)) {
1436 case INPUT_PIN_ATTR_INT:
Takashi Iwai6c819492009-08-10 18:47:44 +02001437 if (fixed)
1438 return; /* already occupied */
1439 fixed = nid;
1440 break;
Takashi Iwai99ae28b2010-09-17 14:42:34 +02001441 case INPUT_PIN_ATTR_UNUSED:
1442 return; /* invalid entry */
1443 default:
Takashi Iwai6c819492009-08-10 18:47:44 +02001444 if (ext)
1445 return; /* already occupied */
1446 ext = nid;
1447 break;
Takashi Iwai6c819492009-08-10 18:47:44 +02001448 }
1449 }
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01001450 if (!ext || !fixed)
1451 return;
Takashi Iwai6c819492009-08-10 18:47:44 +02001452 if (!(get_wcaps(codec, ext) & AC_WCAP_UNSOL_CAP))
1453 return; /* no unsol support */
1454 snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x\n",
1455 ext, fixed);
1456 spec->ext_mic.pin = ext;
1457 spec->int_mic.pin = fixed;
1458 spec->ext_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1459 spec->int_mic.mux_idx = MUX_IDX_UNDEF; /* set later */
1460 spec->auto_mic = 1;
1461 snd_hda_codec_write_cache(codec, spec->ext_mic.pin, 0,
1462 AC_VERB_SET_UNSOLICITED_ENABLE,
1463 AC_USRSP_EN | ALC880_MIC_EVENT);
1464 spec->unsol_event = alc_sku_unsol_event;
1465}
1466
David Henningsson90622912010-10-14 14:50:18 +02001467/* Could be any non-zero and even value. When used as fixup, tells
1468 * the driver to ignore any present sku defines.
1469 */
1470#define ALC_FIXUP_SKU_IGNORE (2)
1471
Kailang Yangda00c242010-03-19 11:23:45 +01001472static int alc_auto_parse_customize_define(struct hda_codec *codec)
1473{
1474 unsigned int ass, tmp, i;
Takashi Iwai7fb56222010-03-22 17:09:47 +01001475 unsigned nid = 0;
Kailang Yangda00c242010-03-19 11:23:45 +01001476 struct alc_spec *spec = codec->spec;
1477
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001478 spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
1479
David Henningsson90622912010-10-14 14:50:18 +02001480 if (spec->cdefine.fixup) {
1481 ass = spec->cdefine.sku_cfg;
1482 if (ass == ALC_FIXUP_SKU_IGNORE)
1483 return -1;
1484 goto do_sku;
1485 }
1486
Kailang Yangda00c242010-03-19 11:23:45 +01001487 ass = codec->subsystem_id & 0xffff;
Takashi Iwaib6cbe512010-07-28 17:43:36 +02001488 if (ass != codec->bus->pci->subsystem_device && (ass & 1))
Kailang Yangda00c242010-03-19 11:23:45 +01001489 goto do_sku;
1490
1491 nid = 0x1d;
1492 if (codec->vendor_id == 0x10ec0260)
1493 nid = 0x17;
1494 ass = snd_hda_codec_get_pincfg(codec, nid);
1495
1496 if (!(ass & 1)) {
1497 printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n",
1498 codec->chip_name, ass);
1499 return -1;
1500 }
1501
1502 /* check sum */
1503 tmp = 0;
1504 for (i = 1; i < 16; i++) {
1505 if ((ass >> i) & 1)
1506 tmp++;
1507 }
1508 if (((ass >> 16) & 0xf) != tmp)
1509 return -1;
1510
1511 spec->cdefine.port_connectivity = ass >> 30;
1512 spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
1513 spec->cdefine.check_sum = (ass >> 16) & 0xf;
1514 spec->cdefine.customization = ass >> 8;
1515do_sku:
1516 spec->cdefine.sku_cfg = ass;
1517 spec->cdefine.external_amp = (ass & 0x38) >> 3;
1518 spec->cdefine.platform_type = (ass & 0x4) >> 2;
1519 spec->cdefine.swap = (ass & 0x2) >> 1;
1520 spec->cdefine.override = ass & 0x1;
1521
1522 snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n",
1523 nid, spec->cdefine.sku_cfg);
1524 snd_printd("SKU: port_connectivity=0x%x\n",
1525 spec->cdefine.port_connectivity);
1526 snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
1527 snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
1528 snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization);
1529 snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
1530 snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
1531 snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap);
1532 snd_printd("SKU: override=0x%x\n", spec->cdefine.override);
1533
1534 return 0;
1535}
1536
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001537/* check subsystem ID and set up device-specific initialization;
1538 * return 1 if initialized, 0 if invalid SSID
1539 */
1540/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
1541 * 31 ~ 16 : Manufacture ID
1542 * 15 ~ 8 : SKU ID
1543 * 7 ~ 0 : Assembly ID
1544 * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
1545 */
1546static int alc_subsystem_id(struct hda_codec *codec,
1547 hda_nid_t porta, hda_nid_t porte,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001548 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001549{
1550 unsigned int ass, tmp, i;
1551 unsigned nid;
1552 struct alc_spec *spec = codec->spec;
1553
David Henningsson90622912010-10-14 14:50:18 +02001554 if (spec->cdefine.fixup) {
1555 ass = spec->cdefine.sku_cfg;
1556 if (ass == ALC_FIXUP_SKU_IGNORE)
1557 return 0;
1558 goto do_sku;
1559 }
1560
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001561 ass = codec->subsystem_id & 0xffff;
1562 if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
1563 goto do_sku;
1564
1565 /* invalid SSID, check the special NID pin defcfg instead */
1566 /*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04001567 * 31~30 : port connectivity
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001568 * 29~21 : reserve
1569 * 20 : PCBEEP input
1570 * 19~16 : Check sum (15:1)
1571 * 15~1 : Custom
1572 * 0 : override
1573 */
1574 nid = 0x1d;
1575 if (codec->vendor_id == 0x10ec0260)
1576 nid = 0x17;
1577 ass = snd_hda_codec_get_pincfg(codec, nid);
1578 snd_printd("realtek: No valid SSID, "
1579 "checking pincfg 0x%08x for NID 0x%x\n",
Takashi Iwaicb6605c2009-04-28 13:03:19 +02001580 ass, nid);
Kailang Yang6227cdc2010-02-25 08:36:52 +01001581 if (!(ass & 1))
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001582 return 0;
1583 if ((ass >> 30) != 1) /* no physical connection */
1584 return 0;
1585
1586 /* check sum */
1587 tmp = 0;
1588 for (i = 1; i < 16; i++) {
1589 if ((ass >> i) & 1)
1590 tmp++;
1591 }
1592 if (((ass >> 16) & 0xf) != tmp)
1593 return 0;
1594do_sku:
1595 snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
1596 ass & 0xffff, codec->vendor_id);
1597 /*
1598 * 0 : override
1599 * 1 : Swap Jack
1600 * 2 : 0 --> Desktop, 1 --> Laptop
1601 * 3~5 : External Amplifier control
1602 * 7~6 : Reserved
1603 */
1604 tmp = (ass & 0x38) >> 3; /* external Amp control */
1605 switch (tmp) {
1606 case 1:
1607 spec->init_amp = ALC_INIT_GPIO1;
1608 break;
1609 case 3:
1610 spec->init_amp = ALC_INIT_GPIO2;
1611 break;
1612 case 7:
1613 spec->init_amp = ALC_INIT_GPIO3;
1614 break;
1615 case 5:
Takashi Iwai5a8cfb42010-11-26 17:11:18 +01001616 default:
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001617 spec->init_amp = ALC_INIT_DEFAULT;
1618 break;
1619 }
1620
1621 /* is laptop or Desktop and enable the function "Mute internal speaker
1622 * when the external headphone out jack is plugged"
1623 */
1624 if (!(ass & 0x8000))
1625 return 1;
1626 /*
1627 * 10~8 : Jack location
1628 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
1629 * 14~13: Resvered
1630 * 15 : 1 --> enable the function "Mute internal speaker
1631 * when the external headphone out jack is plugged"
1632 */
Kailang Yangc9b58002007-10-16 14:30:01 +02001633 if (!spec->autocfg.hp_pins[0]) {
Takashi Iwai01d48252009-10-06 13:21:54 +02001634 hda_nid_t nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001635 tmp = (ass >> 11) & 0x3; /* HP to chassis */
1636 if (tmp == 0)
Takashi Iwai01d48252009-10-06 13:21:54 +02001637 nid = porta;
Kailang Yangc9b58002007-10-16 14:30:01 +02001638 else if (tmp == 1)
Takashi Iwai01d48252009-10-06 13:21:54 +02001639 nid = porte;
Kailang Yangc9b58002007-10-16 14:30:01 +02001640 else if (tmp == 2)
Takashi Iwai01d48252009-10-06 13:21:54 +02001641 nid = portd;
Kailang Yang6227cdc2010-02-25 08:36:52 +01001642 else if (tmp == 3)
1643 nid = porti;
Kailang Yangc9b58002007-10-16 14:30:01 +02001644 else
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001645 return 1;
Takashi Iwai01d48252009-10-06 13:21:54 +02001646 for (i = 0; i < spec->autocfg.line_outs; i++)
1647 if (spec->autocfg.line_out_pins[i] == nid)
1648 return 1;
1649 spec->autocfg.hp_pins[0] = nid;
Kailang Yangc9b58002007-10-16 14:30:01 +02001650 }
1651
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001652 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001653 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001654 return 1;
1655}
Kailang Yangea1fb292008-08-26 12:58:38 +02001656
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001657static void alc_ssid_check(struct hda_codec *codec,
Kailang Yang6227cdc2010-02-25 08:36:52 +01001658 hda_nid_t porta, hda_nid_t porte,
1659 hda_nid_t portd, hda_nid_t porti)
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001660{
Kailang Yang6227cdc2010-02-25 08:36:52 +01001661 if (!alc_subsystem_id(codec, porta, porte, portd, porti)) {
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001662 struct alc_spec *spec = codec->spec;
1663 snd_printd("realtek: "
1664 "Enable default setup for auto mode as fallback\n");
1665 spec->init_amp = ALC_INIT_DEFAULT;
1666 alc_init_auto_hp(codec);
Takashi Iwai6c819492009-08-10 18:47:44 +02001667 alc_init_auto_mic(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02001668 }
Kailang Yangbc9f98a2007-04-12 13:06:07 +02001669}
1670
Takashi Iwai41e41f12005-06-08 14:48:49 +02001671/*
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001672 * Fix-up pin default configurations and add default verbs
Takashi Iwaif95474e2007-07-10 00:47:43 +02001673 */
1674
1675struct alc_pincfg {
1676 hda_nid_t nid;
1677 u32 val;
1678};
1679
Todd Broche1eb5f12010-12-06 11:19:51 -08001680struct alc_model_fixup {
1681 const int id;
1682 const char *name;
1683};
1684
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001685struct alc_fixup {
David Henningsson90622912010-10-14 14:50:18 +02001686 unsigned int sku;
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001687 const struct alc_pincfg *pins;
1688 const struct hda_verb *verbs;
Takashi Iwai9d578832010-11-22 13:29:19 +01001689 void (*func)(struct hda_codec *codec, const struct alc_fixup *fix,
1690 int pre_init);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001691};
1692
Todd Broche1eb5f12010-12-06 11:19:51 -08001693static void __alc_pick_fixup(struct hda_codec *codec,
1694 const struct alc_fixup *fix,
1695 const char *modelname,
1696 int pre_init)
Takashi Iwaif95474e2007-07-10 00:47:43 +02001697{
1698 const struct alc_pincfg *cfg;
David Henningsson90622912010-10-14 14:50:18 +02001699 struct alc_spec *spec;
Takashi Iwaif95474e2007-07-10 00:47:43 +02001700
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001701 cfg = fix->pins;
David Henningsson90622912010-10-14 14:50:18 +02001702 if (pre_init && fix->sku) {
1703#ifdef CONFIG_SND_DEBUG_VERBOSE
1704 snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
Todd Broche1eb5f12010-12-06 11:19:51 -08001705 codec->chip_name, modelname);
David Henningsson90622912010-10-14 14:50:18 +02001706#endif
1707 spec = codec->spec;
1708 spec->cdefine.sku_cfg = fix->sku;
1709 spec->cdefine.fixup = 1;
1710 }
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001711 if (pre_init && cfg) {
1712#ifdef CONFIG_SND_DEBUG_VERBOSE
1713 snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
Todd Broche1eb5f12010-12-06 11:19:51 -08001714 codec->chip_name, modelname);
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001715#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001716 for (; cfg->nid; cfg++)
1717 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
1718 }
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001719 if (!pre_init && fix->verbs) {
1720#ifdef CONFIG_SND_DEBUG_VERBOSE
1721 snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
Todd Broche1eb5f12010-12-06 11:19:51 -08001722 codec->chip_name, modelname);
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001723#endif
Takashi Iwaif8f25ba2009-10-06 08:31:29 +02001724 add_verb(codec->spec, fix->verbs);
Takashi Iwai7fa90e82010-04-12 08:49:00 +02001725 }
Takashi Iwai9d578832010-11-22 13:29:19 +01001726 if (fix->func) {
1727#ifdef CONFIG_SND_DEBUG_VERBOSE
1728 snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-func for %s\n",
Todd Broche1eb5f12010-12-06 11:19:51 -08001729 codec->chip_name, modelname);
Takashi Iwai9d578832010-11-22 13:29:19 +01001730#endif
1731 fix->func(codec, fix, pre_init);
1732 }
Takashi Iwaif95474e2007-07-10 00:47:43 +02001733}
1734
Todd Broche1eb5f12010-12-06 11:19:51 -08001735static void alc_pick_fixup(struct hda_codec *codec,
1736 const struct snd_pci_quirk *quirk,
1737 const struct alc_fixup *fix,
1738 int pre_init)
1739{
1740 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
1741 if (quirk) {
1742 fix += quirk->value;
1743#ifdef CONFIG_SND_DEBUG_VERBOSE
1744 __alc_pick_fixup(codec, fix, quirk->name, pre_init);
1745#else
1746 __alc_pick_fixup(codec, fix, NULL, pre_init);
1747#endif
1748 }
1749}
1750
1751static void alc_pick_fixup_model(struct hda_codec *codec,
1752 const struct alc_model_fixup *models,
1753 const struct snd_pci_quirk *quirk,
1754 const struct alc_fixup *fix,
1755 int pre_init)
1756{
1757 if (codec->modelname && models) {
1758 while (models->name) {
1759 if (!strcmp(codec->modelname, models->name)) {
1760 fix += models->id;
1761 break;
1762 }
1763 models++;
1764 }
1765 __alc_pick_fixup(codec, fix, codec->modelname, pre_init);
1766 } else {
1767 alc_pick_fixup(codec, quirk, fix, pre_init);
1768 }
1769}
1770
Kailang Yang274693f2009-12-03 10:07:50 +01001771static int alc_read_coef_idx(struct hda_codec *codec,
1772 unsigned int coef_idx)
1773{
1774 unsigned int val;
1775 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1776 coef_idx);
1777 val = snd_hda_codec_read(codec, 0x20, 0,
1778 AC_VERB_GET_PROC_COEF, 0);
1779 return val;
1780}
1781
Kailang Yang977ddd62010-09-15 10:02:29 +02001782static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
1783 unsigned int coef_val)
1784{
1785 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
1786 coef_idx);
1787 snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
1788 coef_val);
1789}
1790
Takashi Iwai757899a2010-07-30 10:48:14 +02001791/* set right pin controls for digital I/O */
1792static void alc_auto_init_digital(struct hda_codec *codec)
1793{
1794 struct alc_spec *spec = codec->spec;
1795 int i;
1796 hda_nid_t pin;
1797
1798 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1799 pin = spec->autocfg.dig_out_pins[i];
1800 if (pin) {
1801 snd_hda_codec_write(codec, pin, 0,
1802 AC_VERB_SET_PIN_WIDGET_CONTROL,
1803 PIN_OUT);
1804 }
1805 }
1806 pin = spec->autocfg.dig_in_pin;
1807 if (pin)
1808 snd_hda_codec_write(codec, pin, 0,
1809 AC_VERB_SET_PIN_WIDGET_CONTROL,
1810 PIN_IN);
1811}
1812
1813/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
1814static void alc_auto_parse_digital(struct hda_codec *codec)
1815{
1816 struct alc_spec *spec = codec->spec;
1817 int i, err;
1818 hda_nid_t dig_nid;
1819
1820 /* support multiple SPDIFs; the secondary is set up as a slave */
1821 for (i = 0; i < spec->autocfg.dig_outs; i++) {
1822 err = snd_hda_get_connections(codec,
1823 spec->autocfg.dig_out_pins[i],
1824 &dig_nid, 1);
1825 if (err < 0)
1826 continue;
1827 if (!i) {
1828 spec->multiout.dig_out_nid = dig_nid;
1829 spec->dig_out_type = spec->autocfg.dig_out_type[0];
1830 } else {
1831 spec->multiout.slave_dig_outs = spec->slave_dig_outs;
1832 if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
1833 break;
1834 spec->slave_dig_outs[i - 1] = dig_nid;
1835 }
1836 }
1837
1838 if (spec->autocfg.dig_in_pin) {
Takashi Iwai01fdf182010-09-24 09:09:42 +02001839 dig_nid = codec->start_nid;
1840 for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
1841 unsigned int wcaps = get_wcaps(codec, dig_nid);
1842 if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
1843 continue;
1844 if (!(wcaps & AC_WCAP_DIGITAL))
1845 continue;
1846 if (!(wcaps & AC_WCAP_CONN_LIST))
1847 continue;
1848 err = get_connection_index(codec, dig_nid,
1849 spec->autocfg.dig_in_pin);
1850 if (err >= 0) {
1851 spec->dig_in_nid = dig_nid;
1852 break;
1853 }
1854 }
Takashi Iwai757899a2010-07-30 10:48:14 +02001855 }
1856}
1857
Takashi Iwaif95474e2007-07-10 00:47:43 +02001858/*
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001859 * ALC888
1860 */
1861
1862/*
1863 * 2ch mode
1864 */
1865static struct hda_verb alc888_4ST_ch2_intel_init[] = {
1866/* Mic-in jack as mic in */
1867 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1868 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1869/* Line-in jack as Line in */
1870 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1871 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1872/* Line-Out as Front */
1873 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1874 { } /* end */
1875};
1876
1877/*
1878 * 4ch mode
1879 */
1880static struct hda_verb alc888_4ST_ch4_intel_init[] = {
1881/* Mic-in jack as mic in */
1882 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1883 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
1884/* Line-in jack as Surround */
1885 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1886 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1887/* Line-Out as Front */
1888 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1889 { } /* end */
1890};
1891
1892/*
1893 * 6ch mode
1894 */
1895static struct hda_verb alc888_4ST_ch6_intel_init[] = {
1896/* Mic-in jack as CLFE */
1897 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1898 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1899/* Line-in jack as Surround */
1900 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1901 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1902/* Line-Out as CLFE (workaround because Mic-in is not loud enough) */
1903 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1904 { } /* end */
1905};
1906
1907/*
1908 * 8ch mode
1909 */
1910static struct hda_verb alc888_4ST_ch8_intel_init[] = {
1911/* Mic-in jack as CLFE */
1912 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1913 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1914/* Line-in jack as Surround */
1915 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1916 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
1917/* Line-Out as Side */
1918 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1919 { } /* end */
1920};
1921
1922static struct hda_channel_mode alc888_4ST_8ch_intel_modes[4] = {
1923 { 2, alc888_4ST_ch2_intel_init },
1924 { 4, alc888_4ST_ch4_intel_init },
1925 { 6, alc888_4ST_ch6_intel_init },
1926 { 8, alc888_4ST_ch8_intel_init },
1927};
1928
1929/*
1930 * ALC888 Fujitsu Siemens Amillo xa3530
1931 */
1932
1933static struct hda_verb alc888_fujitsu_xa3530_verbs[] = {
1934/* Front Mic: set to PIN_IN (empty by default) */
1935 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1936/* Connect Internal HP to Front */
1937 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1938 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1939 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
1940/* Connect Bass HP to Front */
1941 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1942 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1943 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
1944/* Connect Line-Out side jack (SPDIF) to Side */
1945 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1946 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1947 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
1948/* Connect Mic jack to CLFE */
1949 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1950 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1951 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
1952/* Connect Line-in jack to Surround */
1953 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1954 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1955 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
1956/* Connect HP out jack to Front */
1957 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1958 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1959 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1960/* Enable unsolicited event for HP jack and Line-out jack */
1961 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1962 {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
1963 {}
1964};
1965
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001966static void alc_automute_amp(struct hda_codec *codec)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001967{
Takashi Iwaibb35feb2010-09-08 15:30:49 +02001968 alc_automute_speaker(codec, 0);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001969}
1970
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001971static void alc_automute_amp_unsol_event(struct hda_codec *codec,
1972 unsigned int res)
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001973{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02001974 if (codec->vendor_id == 0x10ec0880)
1975 res >>= 28;
1976 else
1977 res >>= 26;
1978 if (res == ALC880_HP_EVENT)
1979 alc_automute_amp(codec);
Vincent Petryef8ef5f2008-11-23 11:31:41 +08001980}
1981
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001982static void alc889_automute_setup(struct hda_codec *codec)
Wu Fengguang6732bd02009-07-30 09:19:14 +02001983{
1984 struct alc_spec *spec = codec->spec;
1985
1986 spec->autocfg.hp_pins[0] = 0x15;
1987 spec->autocfg.speaker_pins[0] = 0x14;
1988 spec->autocfg.speaker_pins[1] = 0x16;
1989 spec->autocfg.speaker_pins[2] = 0x17;
1990 spec->autocfg.speaker_pins[3] = 0x19;
1991 spec->autocfg.speaker_pins[4] = 0x1a;
Wu Fengguang6732bd02009-07-30 09:19:14 +02001992}
1993
1994static void alc889_intel_init_hook(struct hda_codec *codec)
1995{
1996 alc889_coef_init(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02001997 alc_automute_amp(codec);
Wu Fengguang6732bd02009-07-30 09:19:14 +02001998}
1999
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002000static void alc888_fujitsu_xa3530_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002001{
2002 struct alc_spec *spec = codec->spec;
2003
2004 spec->autocfg.hp_pins[0] = 0x17; /* line-out */
2005 spec->autocfg.hp_pins[1] = 0x1b; /* hp */
2006 spec->autocfg.speaker_pins[0] = 0x14; /* speaker */
2007 spec->autocfg.speaker_pins[1] = 0x15; /* bass */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002008}
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002009
2010/*
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002011 * ALC888 Acer Aspire 4930G model
2012 */
2013
2014static struct hda_verb alc888_acer_aspire_4930g_verbs[] = {
2015/* Front Mic: set to PIN_IN (empty by default) */
2016 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2017/* Unselect Front Mic by default in input mixer 3 */
2018 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002019/* Enable unsolicited event for HP jack */
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002020 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2021/* Connect Internal HP to front */
2022 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2023 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2024 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2025/* Connect HP out to front */
2026 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2027 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2028 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2029 { }
2030};
2031
Hector Martin3b315d72009-06-02 10:54:19 +02002032/*
Tony Vroond2fd4b02009-06-21 00:40:10 +01002033 * ALC888 Acer Aspire 6530G model
2034 */
2035
2036static struct hda_verb alc888_acer_aspire_6530g_verbs[] = {
Tony Vroond1284182010-04-05 16:30:43 +01002037/* Route to built-in subwoofer as well as speakers */
2038 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2039 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2040 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2041 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002042/* Bias voltage on for external mic port */
2043 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
Emilio López320d5922009-06-25 08:18:44 +02002044/* Front Mic: set to PIN_IN (empty by default) */
2045 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2046/* Unselect Front Mic by default in input mixer 3 */
2047 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002048/* Enable unsolicited event for HP jack */
2049 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2050/* Enable speaker output */
2051 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2052 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Tony Vroond1284182010-04-05 16:30:43 +01002053 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002054/* Enable headphone output */
2055 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2056 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2057 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Tony Vroond1284182010-04-05 16:30:43 +01002058 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
Tony Vroond2fd4b02009-06-21 00:40:10 +01002059 { }
2060};
2061
2062/*
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002063 *ALC888 Acer Aspire 7730G model
2064 */
2065
2066static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
2067/* Bias voltage on for external mic port */
2068 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
2069/* Front Mic: set to PIN_IN (empty by default) */
2070 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2071/* Unselect Front Mic by default in input mixer 3 */
2072 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2073/* Enable unsolicited event for HP jack */
2074 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2075/* Enable speaker output */
2076 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2077 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2078 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
2079/* Enable headphone output */
2080 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
2081 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2082 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2083 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
2084/*Enable internal subwoofer */
2085 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2086 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2087 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
2088 {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
2089 { }
2090};
2091
2092/*
Hector Martin018df412009-06-04 00:13:40 +02002093 * ALC889 Acer Aspire 8930G model
Hector Martin3b315d72009-06-02 10:54:19 +02002094 */
2095
Hector Martin018df412009-06-04 00:13:40 +02002096static struct hda_verb alc889_acer_aspire_8930g_verbs[] = {
Hector Martin3b315d72009-06-02 10:54:19 +02002097/* Front Mic: set to PIN_IN (empty by default) */
2098 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2099/* Unselect Front Mic by default in input mixer 3 */
2100 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
2101/* Enable unsolicited event for HP jack */
2102 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
2103/* Connect Internal Front to Front */
2104 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2105 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2106 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
2107/* Connect Internal Rear to Rear */
2108 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2109 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2110 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
2111/* Connect Internal CLFE to CLFE */
2112 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2113 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2114 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
2115/* Connect HP out to Front */
Hector Martin018df412009-06-04 00:13:40 +02002116 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
Hector Martin3b315d72009-06-02 10:54:19 +02002117 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2118 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
2119/* Enable all DACs */
2120/* DAC DISABLE/MUTE 1? */
2121/* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */
2122 {0x20, AC_VERB_SET_COEF_INDEX, 0x03},
2123 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
2124/* DAC DISABLE/MUTE 2? */
2125/* some bit here disables the other DACs. Init=0x4900 */
2126 {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
2127 {0x20, AC_VERB_SET_PROC_COEF, 0x0000},
Hector Martin018df412009-06-04 00:13:40 +02002128/* DMIC fix
2129 * This laptop has a stereo digital microphone. The mics are only 1cm apart
2130 * which makes the stereo useless. However, either the mic or the ALC889
2131 * makes the signal become a difference/sum signal instead of standard
2132 * stereo, which is annoying. So instead we flip this bit which makes the
2133 * codec replicate the sum signal to both channels, turning it into a
2134 * normal mono mic.
2135 */
2136/* DMIC_CONTROL? Init value = 0x0001 */
2137 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
2138 {0x20, AC_VERB_SET_PROC_COEF, 0x0003},
Hector Martin3b315d72009-06-02 10:54:19 +02002139 { }
2140};
2141
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002142static struct hda_input_mux alc888_2_capture_sources[2] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002143 /* Front mic only available on one ADC */
2144 {
2145 .num_items = 4,
2146 .items = {
2147 { "Mic", 0x0 },
2148 { "Line", 0x2 },
2149 { "CD", 0x4 },
2150 { "Front Mic", 0xb },
2151 },
2152 },
2153 {
2154 .num_items = 3,
2155 .items = {
2156 { "Mic", 0x0 },
2157 { "Line", 0x2 },
2158 { "CD", 0x4 },
2159 },
2160 }
2161};
2162
Tony Vroond2fd4b02009-06-21 00:40:10 +01002163static struct hda_input_mux alc888_acer_aspire_6530_sources[2] = {
2164 /* Interal mic only available on one ADC */
2165 {
Tony Vroon684a8842009-06-26 09:27:50 +01002166 .num_items = 5,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002167 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002168 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002169 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002170 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002171 { "Input Mix", 0xa },
David Henningsson28c4edb2010-12-20 14:24:29 +01002172 { "Internal Mic", 0xb },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002173 },
2174 },
2175 {
Tony Vroon684a8842009-06-26 09:27:50 +01002176 .num_items = 4,
Tony Vroond2fd4b02009-06-21 00:40:10 +01002177 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +01002178 { "Mic", 0x0 },
Tony Vroon684a8842009-06-26 09:27:50 +01002179 { "Line In", 0x2 },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002180 { "CD", 0x4 },
Tony Vroon684a8842009-06-26 09:27:50 +01002181 { "Input Mix", 0xa },
Tony Vroond2fd4b02009-06-21 00:40:10 +01002182 },
2183 }
2184};
2185
Hector Martin018df412009-06-04 00:13:40 +02002186static struct hda_input_mux alc889_capture_sources[3] = {
2187 /* Digital mic only available on first "ADC" */
2188 {
2189 .num_items = 5,
2190 .items = {
2191 { "Mic", 0x0 },
2192 { "Line", 0x2 },
2193 { "CD", 0x4 },
2194 { "Front Mic", 0xb },
2195 { "Input Mix", 0xa },
2196 },
2197 },
2198 {
2199 .num_items = 4,
2200 .items = {
2201 { "Mic", 0x0 },
2202 { "Line", 0x2 },
2203 { "CD", 0x4 },
2204 { "Input Mix", 0xa },
2205 },
2206 },
2207 {
2208 .num_items = 4,
2209 .items = {
2210 { "Mic", 0x0 },
2211 { "Line", 0x2 },
2212 { "CD", 0x4 },
2213 { "Input Mix", 0xa },
2214 },
2215 }
2216};
2217
Vincent Petryef8ef5f2008-11-23 11:31:41 +08002218static struct snd_kcontrol_new alc888_base_mixer[] = {
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002219 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2220 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2221 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2222 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2223 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2224 HDA_OUTPUT),
2225 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2226 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2227 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2228 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
2229 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
2230 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2231 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2232 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2233 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2234 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002235 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002236 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002237 { } /* end */
2238};
2239
Hector Martin556eea92009-12-20 22:51:23 +01002240static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = {
2241 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2242 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
2243 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2244 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
2245 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
2246 HDA_OUTPUT),
2247 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2248 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2249 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2250 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2251 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2252 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002253 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hector Martin556eea92009-12-20 22:51:23 +01002254 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2255 { } /* end */
2256};
2257
2258
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002259static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec)
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002260{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002261 struct alc_spec *spec = codec->spec;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002262
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02002263 spec->autocfg.hp_pins[0] = 0x15;
2264 spec->autocfg.speaker_pins[0] = 0x14;
Łukasz Wojniłowicz7cef4cf2009-11-20 12:14:35 +01002265 spec->autocfg.speaker_pins[1] = 0x16;
2266 spec->autocfg.speaker_pins[2] = 0x17;
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002267}
2268
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002269static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec)
Emilio López320d5922009-06-25 08:18:44 +02002270{
2271 struct alc_spec *spec = codec->spec;
2272
2273 spec->autocfg.hp_pins[0] = 0x15;
2274 spec->autocfg.speaker_pins[0] = 0x14;
2275 spec->autocfg.speaker_pins[1] = 0x16;
2276 spec->autocfg.speaker_pins[2] = 0x17;
Emilio López320d5922009-06-25 08:18:44 +02002277}
2278
Denis Kuplyakovd9477202010-11-24 06:01:09 +01002279static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
2280{
2281 struct alc_spec *spec = codec->spec;
2282
2283 spec->autocfg.hp_pins[0] = 0x15;
2284 spec->autocfg.speaker_pins[0] = 0x14;
2285 spec->autocfg.speaker_pins[1] = 0x16;
2286 spec->autocfg.speaker_pins[2] = 0x17;
2287}
2288
Takashi Iwai4f5d17062009-08-11 18:17:46 +02002289static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
Hector Martin3b315d72009-06-02 10:54:19 +02002290{
2291 struct alc_spec *spec = codec->spec;
2292
2293 spec->autocfg.hp_pins[0] = 0x15;
2294 spec->autocfg.speaker_pins[0] = 0x14;
2295 spec->autocfg.speaker_pins[1] = 0x16;
2296 spec->autocfg.speaker_pins[2] = 0x1b;
Hector Martin3b315d72009-06-02 10:54:19 +02002297}
2298
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08002299/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002300 * ALC880 3-stack model
2301 *
2302 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002303 * Pin assignment: Front = 0x14, Line-In/Surr = 0x1a, Mic/CLFE = 0x18,
2304 * F-Mic = 0x1b, HP = 0x19
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 */
2306
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002307static hda_nid_t alc880_dac_nids[4] = {
2308 /* front, rear, clfe, rear_surr */
2309 0x02, 0x05, 0x04, 0x03
2310};
2311
2312static hda_nid_t alc880_adc_nids[3] = {
2313 /* ADC0-2 */
2314 0x07, 0x08, 0x09,
2315};
2316
2317/* The datasheet says the node 0x07 is connected from inputs,
2318 * but it shows zero connection in the real implementation on some devices.
Kailang Yangdf694da2005-12-05 19:42:22 +01002319 * Note: this is a 915GAV bug, fixed on 915GLV
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002321static hda_nid_t alc880_adc_nids_alt[2] = {
2322 /* ADC1-2 */
2323 0x08, 0x09,
2324};
2325
2326#define ALC880_DIGOUT_NID 0x06
2327#define ALC880_DIGIN_NID 0x0a
2328
2329static struct hda_input_mux alc880_capture_source = {
2330 .num_items = 4,
2331 .items = {
2332 { "Mic", 0x0 },
2333 { "Front Mic", 0x3 },
2334 { "Line", 0x2 },
2335 { "CD", 0x4 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002337};
2338
2339/* channel source setting (2/6 channel selection for 3-stack) */
2340/* 2ch mode */
2341static struct hda_verb alc880_threestack_ch2_init[] = {
2342 /* set line-in to input, mute it */
2343 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2344 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2345 /* set mic-in to input vref 80%, mute it */
2346 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2347 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 { } /* end */
2349};
2350
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002351/* 6ch mode */
2352static struct hda_verb alc880_threestack_ch6_init[] = {
2353 /* set line-in to output, unmute it */
2354 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2355 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2356 /* set mic-in to output, unmute it */
2357 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2358 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2359 { } /* end */
2360};
2361
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002362static struct hda_channel_mode alc880_threestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002363 { 2, alc880_threestack_ch2_init },
2364 { 6, alc880_threestack_ch6_init },
2365};
2366
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002367static struct snd_kcontrol_new alc880_three_stack_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02002368 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002369 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002370 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002371 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02002372 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2373 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002374 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2375 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2377 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2378 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2379 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2380 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2381 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2382 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
2383 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 HDA_CODEC_MUTE("Headphone Playback Switch", 0x19, 0x0, HDA_OUTPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002385 {
2386 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2387 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002388 .info = alc_ch_mode_info,
2389 .get = alc_ch_mode_get,
2390 .put = alc_ch_mode_put,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002391 },
2392 { } /* end */
2393};
2394
2395/* capture mixer elements */
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002396static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
2397 struct snd_ctl_elem_info *uinfo)
2398{
2399 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2400 struct alc_spec *spec = codec->spec;
2401 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002402
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002403 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002404 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2405 HDA_INPUT);
2406 err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002407 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002408 return err;
2409}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002411static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2412 unsigned int size, unsigned int __user *tlv)
2413{
2414 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2415 struct alc_spec *spec = codec->spec;
2416 int err;
2417
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002418 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002419 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0,
2420 HDA_INPUT);
2421 err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002422 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002423 return err;
2424}
2425
2426typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
2427 struct snd_ctl_elem_value *ucontrol);
2428
2429static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
2430 struct snd_ctl_elem_value *ucontrol,
2431 getput_call_t func)
2432{
2433 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2434 struct alc_spec *spec = codec->spec;
2435 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2436 int err;
2437
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002438 mutex_lock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002439 kcontrol->private_value = HDA_COMPOSE_AMP_VAL(spec->adc_nids[adc_idx],
2440 3, 0, HDA_INPUT);
2441 err = func(kcontrol, ucontrol);
Wu Fengguang5a9e02e2009-01-09 16:45:24 +08002442 mutex_unlock(&codec->control_mutex);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002443 return err;
2444}
2445
2446static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
2447 struct snd_ctl_elem_value *ucontrol)
2448{
2449 return alc_cap_getput_caller(kcontrol, ucontrol,
2450 snd_hda_mixer_amp_volume_get);
2451}
2452
2453static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
2454 struct snd_ctl_elem_value *ucontrol)
2455{
2456 return alc_cap_getput_caller(kcontrol, ucontrol,
2457 snd_hda_mixer_amp_volume_put);
2458}
2459
2460/* capture mixer elements */
2461#define alc_cap_sw_info snd_ctl_boolean_stereo_info
2462
2463static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
2464 struct snd_ctl_elem_value *ucontrol)
2465{
2466 return alc_cap_getput_caller(kcontrol, ucontrol,
2467 snd_hda_mixer_amp_switch_get);
2468}
2469
2470static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
2471 struct snd_ctl_elem_value *ucontrol)
2472{
2473 return alc_cap_getput_caller(kcontrol, ucontrol,
2474 snd_hda_mixer_amp_switch_put);
2475}
2476
Takashi Iwaia23b6882009-03-23 15:21:36 +01002477#define _DEFINE_CAPMIX(num) \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002478 { \
2479 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2480 .name = "Capture Switch", \
2481 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
2482 .count = num, \
2483 .info = alc_cap_sw_info, \
2484 .get = alc_cap_sw_get, \
2485 .put = alc_cap_sw_put, \
2486 }, \
2487 { \
2488 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2489 .name = "Capture Volume", \
2490 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
2491 SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
2492 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
2493 .count = num, \
2494 .info = alc_cap_vol_info, \
2495 .get = alc_cap_vol_get, \
2496 .put = alc_cap_vol_put, \
2497 .tlv = { .c = alc_cap_vol_tlv }, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002498 }
2499
2500#define _DEFINE_CAPSRC(num) \
Takashi Iwai3c3e9892008-10-31 17:48:56 +01002501 { \
2502 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2503 /* .name = "Capture Source", */ \
2504 .name = "Input Source", \
2505 .count = num, \
2506 .info = alc_mux_enum_info, \
2507 .get = alc_mux_enum_get, \
2508 .put = alc_mux_enum_put, \
Takashi Iwaia23b6882009-03-23 15:21:36 +01002509 }
2510
2511#define DEFINE_CAPMIX(num) \
2512static struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
2513 _DEFINE_CAPMIX(num), \
2514 _DEFINE_CAPSRC(num), \
2515 { } /* end */ \
2516}
2517
2518#define DEFINE_CAPMIX_NOSRC(num) \
2519static struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
2520 _DEFINE_CAPMIX(num), \
2521 { } /* end */ \
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002522}
2523
2524/* up to three ADCs */
2525DEFINE_CAPMIX(1);
2526DEFINE_CAPMIX(2);
2527DEFINE_CAPMIX(3);
Takashi Iwaia23b6882009-03-23 15:21:36 +01002528DEFINE_CAPMIX_NOSRC(1);
2529DEFINE_CAPMIX_NOSRC(2);
2530DEFINE_CAPMIX_NOSRC(3);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002531
2532/*
2533 * ALC880 5-stack model
2534 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002535 * DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0d),
2536 * Side = 0x02 (0xd)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002537 * Pin assignment: Front = 0x14, Surr = 0x17, CLFE = 0x16
2538 * Line-In/Side = 0x1a, Mic = 0x18, F-Mic = 0x1b, HP = 0x19
2539 */
2540
2541/* additional mixers to alc880_three_stack_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002542static struct snd_kcontrol_new alc880_five_stack_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002543 HDA_CODEC_VOLUME("Side Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002544 HDA_BIND_MUTE("Side Playback Switch", 0x0d, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 { } /* end */
2546};
2547
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002548/* channel source setting (6/8 channel selection for 5-stack) */
2549/* 6ch mode */
2550static struct hda_verb alc880_fivestack_ch6_init[] = {
2551 /* set line-in to input, mute it */
2552 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2553 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02002554 { } /* end */
2555};
2556
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002557/* 8ch mode */
2558static struct hda_verb alc880_fivestack_ch8_init[] = {
2559 /* set line-in to output, unmute it */
2560 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2561 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2562 { } /* end */
2563};
2564
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002565static struct hda_channel_mode alc880_fivestack_modes[2] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002566 { 6, alc880_fivestack_ch6_init },
2567 { 8, alc880_fivestack_ch8_init },
2568};
2569
2570
2571/*
2572 * ALC880 6-stack model
2573 *
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002574 * DAC: Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e),
2575 * Side = 0x05 (0x0f)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002576 * Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, Side = 0x17,
2577 * Mic = 0x18, F-Mic = 0x19, Line = 0x1a, HP = 0x1b
2578 */
2579
2580static hda_nid_t alc880_6st_dac_nids[4] = {
2581 /* front, rear, clfe, rear_surr */
2582 0x02, 0x03, 0x04, 0x05
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02002583};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002584
2585static struct hda_input_mux alc880_6stack_capture_source = {
2586 .num_items = 4,
2587 .items = {
2588 { "Mic", 0x0 },
2589 { "Front Mic", 0x1 },
2590 { "Line", 0x2 },
2591 { "CD", 0x4 },
2592 },
2593};
2594
2595/* fixed 8-channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002596static struct hda_channel_mode alc880_sixstack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002597 { 8, NULL },
2598};
2599
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002600static struct snd_kcontrol_new alc880_six_stack_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002601 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002602 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002603 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002604 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002605 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2606 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002607 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2608 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002609 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002610 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002611 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2612 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2613 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2614 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2615 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2616 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2617 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2618 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002619 {
2620 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2621 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002622 .info = alc_ch_mode_info,
2623 .get = alc_ch_mode_get,
2624 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002625 },
2626 { } /* end */
2627};
2628
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002629
2630/*
2631 * ALC880 W810 model
2632 *
2633 * W810 has rear IO for:
2634 * Front (DAC 02)
2635 * Surround (DAC 03)
2636 * Center/LFE (DAC 04)
2637 * Digital out (06)
2638 *
2639 * The system also has a pair of internal speakers, and a headphone jack.
2640 * These are both connected to Line2 on the codec, hence to DAC 02.
Kailang Yangea1fb292008-08-26 12:58:38 +02002641 *
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002642 * There is a variable resistor to control the speaker or headphone
2643 * volume. This is a hardware-only device without a software API.
2644 *
2645 * Plugging headphones in will disable the internal speakers. This is
2646 * implemented in hardware, not via the driver using jack sense. In
2647 * a similar fashion, plugging into the rear socket marked "front" will
2648 * disable both the speakers and headphones.
2649 *
2650 * For input, there's a microphone jack, and an "audio in" jack.
2651 * These may not do anything useful with this driver yet, because I
2652 * haven't setup any initialization verbs for these yet...
2653 */
2654
2655static hda_nid_t alc880_w810_dac_nids[3] = {
2656 /* front, rear/surround, clfe */
2657 0x02, 0x03, 0x04
2658};
2659
2660/* fixed 6 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002661static struct hda_channel_mode alc880_w810_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002662 { 6, NULL }
2663};
2664
2665/* Pin assignment: Front = 0x14, Surr = 0x15, CLFE = 0x16, HP = 0x1b */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002666static struct snd_kcontrol_new alc880_w810_base_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002667 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002668 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002669 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002670 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002671 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2672 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002673 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2674 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002675 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2676 { } /* end */
2677};
2678
2679
2680/*
2681 * Z710V model
2682 *
2683 * DAC: Front = 0x02 (0x0c), HP = 0x03 (0x0d)
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002684 * Pin assignment: Front = 0x14, HP = 0x15, Mic = 0x18, Mic2 = 0x19(?),
2685 * Line = 0x1a
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002686 */
2687
2688static hda_nid_t alc880_z71v_dac_nids[1] = {
2689 0x02
2690};
2691#define ALC880_Z71V_HP_DAC 0x03
2692
2693/* fixed 2 channels */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01002694static struct hda_channel_mode alc880_2_jack_modes[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002695 { 2, NULL }
2696};
2697
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002698static struct snd_kcontrol_new alc880_z71v_mixer[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002699 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002700 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002701 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002702 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002703 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2704 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2705 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2706 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2707 { } /* end */
2708};
2709
2710
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002711/*
2712 * ALC880 F1734 model
2713 *
2714 * DAC: HP = 0x02 (0x0c), Front = 0x03 (0x0d)
2715 * Pin assignment: HP = 0x14, Front = 0x15, Mic = 0x18
2716 */
2717
2718static hda_nid_t alc880_f1734_dac_nids[1] = {
2719 0x03
2720};
2721#define ALC880_F1734_HP_DAC 0x02
2722
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002723static struct snd_kcontrol_new alc880_f1734_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002724 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002725 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01002726 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2727 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002728 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2729 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai937b4162008-02-11 14:52:36 +01002730 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2731 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002732 { } /* end */
2733};
2734
Takashi Iwai937b4162008-02-11 14:52:36 +01002735static struct hda_input_mux alc880_f1734_capture_source = {
2736 .num_items = 2,
2737 .items = {
2738 { "Mic", 0x1 },
2739 { "CD", 0x4 },
2740 },
2741};
2742
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002743
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002744/*
2745 * ALC880 ASUS model
2746 *
2747 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2748 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2749 * Mic = 0x18, Line = 0x1a
2750 */
2751
2752#define alc880_asus_dac_nids alc880_w810_dac_nids /* identical with w810 */
2753#define alc880_asus_modes alc880_threestack_modes /* 2/6 channel mode */
2754
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002755static struct snd_kcontrol_new alc880_asus_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002756 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002757 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002758 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002759 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002760 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2761 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01002762 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2763 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002764 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2765 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2766 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2767 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2768 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2769 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002770 {
2771 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2772 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01002773 .info = alc_ch_mode_info,
2774 .get = alc_ch_mode_get,
2775 .put = alc_ch_mode_put,
Takashi Iwai16ded522005-06-10 19:58:24 +02002776 },
2777 { } /* end */
2778};
2779
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002780/*
2781 * ALC880 ASUS W1V model
2782 *
2783 * DAC: HP/Front = 0x02 (0x0c), Surr = 0x03 (0x0d), CLFE = 0x04 (0x0e)
2784 * Pin assignment: HP/Front = 0x14, Surr = 0x15, CLFE = 0x16,
2785 * Mic = 0x18, Line = 0x1a, Line2 = 0x1b
2786 */
2787
2788/* additional mixers to alc880_asus_mixer */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01002789static struct snd_kcontrol_new alc880_asus_w1v_mixer[] = {
Takashi Iwai16ded522005-06-10 19:58:24 +02002790 HDA_CODEC_VOLUME("Line2 Playback Volume", 0x0b, 0x03, HDA_INPUT),
2791 HDA_CODEC_MUTE("Line2 Playback Switch", 0x0b, 0x03, HDA_INPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02002792 { } /* end */
2793};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002794
Kailang Yangdf694da2005-12-05 19:42:22 +01002795/* TCL S700 */
2796static struct snd_kcontrol_new alc880_tcl_s700_mixer[] = {
2797 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2798 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
2799 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
2800 HDA_CODEC_VOLUME("CD Playback Volume", 0x0B, 0x04, HDA_INPUT),
2801 HDA_CODEC_MUTE("CD Playback Switch", 0x0B, 0x04, HDA_INPUT),
2802 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0B, 0x0, HDA_INPUT),
2803 HDA_CODEC_MUTE("Mic Playback Switch", 0x0B, 0x0, HDA_INPUT),
2804 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
2805 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01002806 { } /* end */
2807};
2808
Kailang Yangccc656c2006-10-17 12:32:26 +02002809/* Uniwill */
2810static struct snd_kcontrol_new alc880_uniwill_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002811 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2812 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2813 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2814 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002815 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
2816 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
2817 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
2818 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
2819 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2820 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
2821 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
2822 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
2823 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2824 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2825 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2826 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002827 {
2828 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2829 .name = "Channel Mode",
2830 .info = alc_ch_mode_info,
2831 .get = alc_ch_mode_get,
2832 .put = alc_ch_mode_put,
2833 },
2834 { } /* end */
2835};
2836
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002837static struct snd_kcontrol_new alc880_fujitsu_mixer[] = {
2838 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2839 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2840 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2841 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
2842 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
2843 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +01002844 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2845 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01002846 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
2847 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01002848 { } /* end */
2849};
2850
Kailang Yangccc656c2006-10-17 12:32:26 +02002851static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002852 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
2853 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
2854 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
2855 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02002856 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
2857 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
2858 { } /* end */
2859};
2860
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861/*
Takashi Iwai2134ea42008-01-10 16:53:55 +01002862 * virtual master controls
2863 */
2864
2865/*
2866 * slave controls for virtual master
2867 */
2868static const char *alc_slave_vols[] = {
2869 "Front Playback Volume",
2870 "Surround Playback Volume",
2871 "Center Playback Volume",
2872 "LFE Playback Volume",
2873 "Side Playback Volume",
2874 "Headphone Playback Volume",
2875 "Speaker Playback Volume",
2876 "Mono Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002877 "Line-Out Playback Volume",
Takashi Iwai26f5df22008-11-03 17:39:46 +01002878 "PCM Playback Volume",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002879 NULL,
2880};
2881
2882static const char *alc_slave_sws[] = {
2883 "Front Playback Switch",
2884 "Surround Playback Switch",
2885 "Center Playback Switch",
2886 "LFE Playback Switch",
2887 "Side Playback Switch",
2888 "Headphone Playback Switch",
2889 "Speaker Playback Switch",
2890 "Mono Playback Switch",
Takashi Iwaiedb54a52008-01-29 12:47:02 +01002891 "IEC958 Playback Switch",
Takashi Iwai23033b22009-12-08 12:36:52 +01002892 "Line-Out Playback Switch",
2893 "PCM Playback Switch",
Takashi Iwai2134ea42008-01-10 16:53:55 +01002894 NULL,
2895};
2896
2897/*
Takashi Iwaie9edcee2005-06-13 14:16:38 +02002898 * build control elements
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 */
Takashi Iwai603c4012008-07-30 15:01:44 +02002900
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002901#define NID_MAPPING (-1)
2902
2903#define SUBDEV_SPEAKER_ (0 << 6)
2904#define SUBDEV_HP_ (1 << 6)
2905#define SUBDEV_LINE_ (2 << 6)
2906#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f))
2907#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f))
2908#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f))
2909
Takashi Iwai603c4012008-07-30 15:01:44 +02002910static void alc_free_kctls(struct hda_codec *codec);
2911
Takashi Iwai67d634c2009-11-16 15:35:59 +01002912#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002913/* additional beep mixers; the actual parameters are overwritten at build */
2914static struct snd_kcontrol_new alc_beep_mixer[] = {
2915 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +02002916 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002917 { } /* end */
2918};
Takashi Iwai67d634c2009-11-16 15:35:59 +01002919#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002920
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921static int alc_build_controls(struct hda_codec *codec)
2922{
2923 struct alc_spec *spec = codec->spec;
Takashi Iwai2f44f842010-06-22 11:12:32 +02002924 struct snd_kcontrol *kctl = NULL;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002925 struct snd_kcontrol_new *knew;
2926 int i, j, err;
2927 unsigned int u;
2928 hda_nid_t nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
2930 for (i = 0; i < spec->num_mixers; i++) {
2931 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
2932 if (err < 0)
2933 return err;
2934 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01002935 if (spec->cap_mixer) {
2936 err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
2937 if (err < 0)
2938 return err;
2939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 if (spec->multiout.dig_out_nid) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02002941 err = snd_hda_create_spdif_out_ctls(codec,
2942 spec->multiout.dig_out_nid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 if (err < 0)
2944 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002945 if (!spec->no_analog) {
2946 err = snd_hda_create_spdif_share_sw(codec,
2947 &spec->multiout);
2948 if (err < 0)
2949 return err;
2950 spec->multiout.share_spdif = 1;
2951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 }
2953 if (spec->dig_in_nid) {
2954 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
2955 if (err < 0)
2956 return err;
2957 }
Takashi Iwai2134ea42008-01-10 16:53:55 +01002958
Takashi Iwai67d634c2009-11-16 15:35:59 +01002959#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002960 /* create beep controls if needed */
2961 if (spec->beep_amp) {
2962 struct snd_kcontrol_new *knew;
2963 for (knew = alc_beep_mixer; knew->name; knew++) {
2964 struct snd_kcontrol *kctl;
2965 kctl = snd_ctl_new1(knew, codec);
2966 if (!kctl)
2967 return -ENOMEM;
2968 kctl->private_value = spec->beep_amp;
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01002969 err = snd_hda_ctl_add(codec, 0, kctl);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002970 if (err < 0)
2971 return err;
2972 }
2973 }
Takashi Iwai67d634c2009-11-16 15:35:59 +01002974#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01002975
Takashi Iwai2134ea42008-01-10 16:53:55 +01002976 /* if we have no master control, let's create it */
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002977 if (!spec->no_analog &&
2978 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002979 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +01002980 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002981 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002982 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +01002983 vmaster_tlv, alc_slave_vols);
Takashi Iwai2134ea42008-01-10 16:53:55 +01002984 if (err < 0)
2985 return err;
2986 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +01002987 if (!spec->no_analog &&
2988 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
Takashi Iwai2134ea42008-01-10 16:53:55 +01002989 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
2990 NULL, alc_slave_sws);
2991 if (err < 0)
2992 return err;
2993 }
2994
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002995 /* assign Capture Source enums to NID */
Takashi Iwaifbe618f2010-06-11 11:24:58 +02002996 if (spec->capsrc_nids || spec->adc_nids) {
2997 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
2998 if (!kctl)
2999 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
3000 for (i = 0; kctl && i < kctl->count; i++) {
3001 hda_nid_t *nids = spec->capsrc_nids;
3002 if (!nids)
3003 nids = spec->adc_nids;
3004 err = snd_hda_add_nid(codec, kctl, i, nids[i]);
3005 if (err < 0)
3006 return err;
3007 }
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01003008 }
3009 if (spec->cap_mixer) {
3010 const char *kname = kctl ? kctl->id.name : NULL;
3011 for (knew = spec->cap_mixer; knew->name; knew++) {
3012 if (kname && strcmp(knew->name, kname) == 0)
3013 continue;
3014 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3015 for (i = 0; kctl && i < kctl->count; i++) {
3016 err = snd_hda_add_nid(codec, kctl, i,
3017 spec->adc_nids[i]);
3018 if (err < 0)
3019 return err;
3020 }
3021 }
3022 }
3023
3024 /* other nid->control mapping */
3025 for (i = 0; i < spec->num_mixers; i++) {
3026 for (knew = spec->mixers[i]; knew->name; knew++) {
3027 if (knew->iface != NID_MAPPING)
3028 continue;
3029 kctl = snd_hda_find_mixer_ctl(codec, knew->name);
3030 if (kctl == NULL)
3031 continue;
3032 u = knew->subdevice;
3033 for (j = 0; j < 4; j++, u >>= 8) {
3034 nid = u & 0x3f;
3035 if (nid == 0)
3036 continue;
3037 switch (u & 0xc0) {
3038 case SUBDEV_SPEAKER_:
3039 nid = spec->autocfg.speaker_pins[nid];
3040 break;
3041 case SUBDEV_LINE_:
3042 nid = spec->autocfg.line_out_pins[nid];
3043 break;
3044 case SUBDEV_HP_:
3045 nid = spec->autocfg.hp_pins[nid];
3046 break;
3047 default:
3048 continue;
3049 }
3050 err = snd_hda_add_nid(codec, kctl, 0, nid);
3051 if (err < 0)
3052 return err;
3053 }
3054 u = knew->private_value;
3055 for (j = 0; j < 4; j++, u >>= 8) {
3056 nid = u & 0xff;
3057 if (nid == 0)
3058 continue;
3059 err = snd_hda_add_nid(codec, kctl, 0, nid);
3060 if (err < 0)
3061 return err;
3062 }
3063 }
3064 }
Takashi Iwaibae84e72010-03-22 08:30:20 +01003065
3066 alc_free_kctls(codec); /* no longer needed */
3067
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 return 0;
3069}
3070
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003071
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072/*
3073 * initialize the codec volumes, etc
3074 */
3075
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003076/*
3077 * generic initialization of ADC, input mixers and output mixers
3078 */
3079static struct hda_verb alc880_volume_init_verbs[] = {
3080 /*
3081 * Unmute ADC0-2 and set the default input to mic-in
3082 */
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003083 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003084 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003085 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003086 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02003087 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003088 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003090 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
3091 * mixer widget
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003092 * Note: PASD motherboards uses the Line In 2 as the input for front
3093 * panel mic (mic 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003095 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02003096 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3097 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3098 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3099 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3100 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3101 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3102 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003104 /*
3105 * Set up output mixers (0x0c - 0x0f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003107 /* set vol=0 to output mixers */
3108 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3109 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3110 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3111 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3112 /* set up input amps for analog loopback */
3113 /* Amp Indices: DAC = 0, mixer = 1 */
Takashi Iwai05acb862005-06-10 19:50:25 +02003114 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3115 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003116 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3117 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003118 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3119 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai05acb862005-06-10 19:50:25 +02003120 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3121 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
3123 { }
3124};
3125
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003126/*
3127 * 3-stack pin configuration:
3128 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
3129 */
3130static struct hda_verb alc880_pin_3stack_init_verbs[] = {
3131 /*
3132 * preset connection lists of input pins
3133 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3134 */
3135 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3136 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3137 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3138
3139 /*
3140 * Set pin mode and muting
3141 */
3142 /* set front pin widgets 0x14 for output */
3143 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3144 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3145 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3146 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3147 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3148 /* Mic2 (as headphone out) for HP output */
3149 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3150 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3151 /* Line In pin widget for input */
3152 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3153 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3154 /* Line2 (as front mic) pin widget for input and vref at 80% */
3155 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3156 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3157 /* CD pin widget for input */
3158 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3159
3160 { }
3161};
3162
3163/*
3164 * 5-stack pin configuration:
3165 * front = 0x14, surround = 0x17, clfe = 0x16, mic = 0x18, HP = 0x19,
3166 * line-in/side = 0x1a, f-mic = 0x1b
3167 */
3168static struct hda_verb alc880_pin_5stack_init_verbs[] = {
3169 /*
3170 * preset connection lists of input pins
3171 * 0 = front, 1 = rear_surr, 2 = CLFE, 3 = surround
3172 */
3173 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3174 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/side */
3175
3176 /*
3177 * Set pin mode and muting
3178 */
3179 /* set pin widgets 0x14-0x17 for output */
Takashi Iwai05acb862005-06-10 19:50:25 +02003180 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3181 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3182 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3183 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003184 /* unmute pins for output (no gain on this amp) */
3185 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3186 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3187 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3188 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3189
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02003191 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003192 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3193 /* Mic2 (as headphone out) for HP output */
3194 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003195 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003196 /* Line In pin widget for input */
3197 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3198 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3199 /* Line2 (as front mic) pin widget for input and vref at 80% */
3200 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3201 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3202 /* CD pin widget for input */
3203 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
3205 { }
3206};
3207
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003208/*
3209 * W810 pin configuration:
3210 * front = 0x14, surround = 0x15, clfe = 0x16, HP = 0x1b
3211 */
3212static struct hda_verb alc880_pin_w810_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 /* hphone/speaker input selector: front DAC */
3214 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
3215
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003216 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3217 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3218 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3219 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3220 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3221 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3222
3223 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai05acb862005-06-10 19:50:25 +02003224 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 { }
3227};
3228
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003229/*
3230 * Z71V pin configuration:
3231 * Speaker-out = 0x14, HP = 0x15, Mic = 0x18, Line-in = 0x1a, Mic2 = 0x1b (?)
3232 */
3233static struct hda_verb alc880_pin_z71v_init_verbs[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02003234 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003235 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai05acb862005-06-10 19:50:25 +02003236 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003237 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003238
Takashi Iwai16ded522005-06-10 19:58:24 +02003239 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003240 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003241 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003242 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidfc0ff62005-05-12 14:31:49 +02003243
3244 { }
3245};
3246
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003247/*
3248 * 6-stack pin configuration:
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003249 * front = 0x14, surr = 0x15, clfe = 0x16, side = 0x17, mic = 0x18,
3250 * f-mic = 0x19, line = 0x1a, HP = 0x1b
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003251 */
3252static struct hda_verb alc880_pin_6stack_init_verbs[] = {
3253 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3254
Takashi Iwai16ded522005-06-10 19:58:24 +02003255 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003256 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003257 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003258 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003259 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003260 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003261 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003262 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3263
Takashi Iwai16ded522005-06-10 19:58:24 +02003264 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003265 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003266 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003267 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003268 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003269 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003270 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai16ded522005-06-10 19:58:24 +02003271 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai16ded522005-06-10 19:58:24 +02003272 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003273
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003274 { }
3275};
Takashi Iwai16ded522005-06-10 19:58:24 +02003276
Kailang Yangccc656c2006-10-17 12:32:26 +02003277/*
3278 * Uniwill pin configuration:
3279 * HP = 0x14, InternalSpeaker = 0x15, mic = 0x18, internal mic = 0x19,
3280 * line = 0x1a
3281 */
3282static struct hda_verb alc880_uniwill_init_verbs[] = {
3283 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3284
3285 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3286 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3287 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3288 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3289 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3290 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3291 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3292 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3293 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3294 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3295 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3296 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3297 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3298 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3299
3300 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3301 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3302 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3303 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3304 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3305 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3306 /* {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, */
3307 /* {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
3308 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3309
3310 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3311 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
3312
3313 { }
3314};
3315
3316/*
3317* Uniwill P53
Kailang Yangea1fb292008-08-26 12:58:38 +02003318* HP = 0x14, InternalSpeaker = 0x15, mic = 0x19,
Kailang Yangccc656c2006-10-17 12:32:26 +02003319 */
3320static struct hda_verb alc880_uniwill_p53_init_verbs[] = {
3321 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3322
3323 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3324 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3325 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3326 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3327 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3328 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3329 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3330 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3331 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3332 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3333 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
3334 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
3335
3336 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3337 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3338 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3339 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3340 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3341 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3342
3343 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3344 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_DCVOL_EVENT},
3345
3346 { }
3347};
3348
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01003349static struct hda_verb alc880_beep_init_verbs[] = {
3350 { 0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) },
3351 { }
3352};
3353
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003354/* auto-toggle front mic */
Anisse Astiereeb43382010-12-16 12:19:47 +01003355static void alc88x_simple_mic_automute(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003356{
3357 unsigned int present;
3358 unsigned char bits;
Kailang Yangccc656c2006-10-17 12:32:26 +02003359
Wu Fengguang864f92b2009-11-18 12:38:02 +08003360 present = snd_hda_jack_detect(codec, 0x18);
Takashi Iwai47fd8302007-08-10 17:11:07 +02003361 bits = present ? HDA_AMP_MUTE : 0;
3362 snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003363}
3364
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003365static void alc880_uniwill_setup(struct hda_codec *codec)
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003366{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003367 struct alc_spec *spec = codec->spec;
3368
3369 spec->autocfg.hp_pins[0] = 0x14;
3370 spec->autocfg.speaker_pins[0] = 0x15;
3371 spec->autocfg.speaker_pins[0] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003372}
3373
3374static void alc880_uniwill_init_hook(struct hda_codec *codec)
3375{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003376 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01003377 alc88x_simple_mic_automute(codec);
Kailang Yangccc656c2006-10-17 12:32:26 +02003378}
3379
3380static void alc880_uniwill_unsol_event(struct hda_codec *codec,
3381 unsigned int res)
3382{
3383 /* Looks like the unsol event is incompatible with the standard
3384 * definition. 4bit tag is placed at 28 bit!
3385 */
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003386 switch (res >> 28) {
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003387 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01003388 alc88x_simple_mic_automute(codec);
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003389 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003390 default:
3391 alc_automute_amp_unsol_event(codec, res);
3392 break;
Takashi Iwai458a4fa2007-05-05 12:18:40 +02003393 }
Kailang Yangccc656c2006-10-17 12:32:26 +02003394}
3395
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003396static void alc880_uniwill_p53_setup(struct hda_codec *codec)
Kailang Yangccc656c2006-10-17 12:32:26 +02003397{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003398 struct alc_spec *spec = codec->spec;
Kailang Yangccc656c2006-10-17 12:32:26 +02003399
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003400 spec->autocfg.hp_pins[0] = 0x14;
3401 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yangccc656c2006-10-17 12:32:26 +02003402}
3403
3404static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec)
3405{
3406 unsigned int present;
Kailang Yangea1fb292008-08-26 12:58:38 +02003407
Kailang Yangccc656c2006-10-17 12:32:26 +02003408 present = snd_hda_codec_read(codec, 0x21, 0,
Takashi Iwai47fd8302007-08-10 17:11:07 +02003409 AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
3410 present &= HDA_AMP_VOLMASK;
3411 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0,
3412 HDA_AMP_VOLMASK, present);
3413 snd_hda_codec_amp_stereo(codec, 0x0d, HDA_OUTPUT, 0,
3414 HDA_AMP_VOLMASK, present);
Kailang Yangccc656c2006-10-17 12:32:26 +02003415}
Takashi Iwai47fd8302007-08-10 17:11:07 +02003416
Kailang Yangccc656c2006-10-17 12:32:26 +02003417static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec,
3418 unsigned int res)
3419{
3420 /* Looks like the unsol event is incompatible with the standard
3421 * definition. 4bit tag is placed at 28 bit!
3422 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02003423 if ((res >> 28) == ALC880_DCVOL_EVENT)
Kailang Yangccc656c2006-10-17 12:32:26 +02003424 alc880_uniwill_p53_dcvol_automute(codec);
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003425 else
3426 alc_automute_amp_unsol_event(codec, res);
Kailang Yangccc656c2006-10-17 12:32:26 +02003427}
3428
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003429/*
3430 * F1734 pin configuration:
3431 * HP = 0x14, speaker-out = 0x15, mic = 0x18
3432 */
3433static struct hda_verb alc880_pin_f1734_init_verbs[] = {
Michael Gruberee7a9c72008-03-10 11:30:59 +01003434 {0x07, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003435 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3436 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3437 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3438 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3439
3440 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3441 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3442 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3443 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3444
3445 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3446 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Michael Gruberee7a9c72008-03-10 11:30:59 +01003447 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003448 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3449 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3450 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3451 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3452 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3453 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai16ded522005-06-10 19:58:24 +02003454
Takashi Iwai937b4162008-02-11 14:52:36 +01003455 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
3456 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_DCVOL_EVENT},
3457
Takashi Iwai16ded522005-06-10 19:58:24 +02003458 { }
3459};
3460
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003461/*
3462 * ASUS pin configuration:
3463 * HP/front = 0x14, surr = 0x15, clfe = 0x16, mic = 0x18, line = 0x1a
3464 */
3465static struct hda_verb alc880_pin_asus_init_verbs[] = {
3466 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02},
3467 {0x11, AC_VERB_SET_CONNECT_SEL, 0x00},
3468 {0x12, AC_VERB_SET_CONNECT_SEL, 0x01},
3469 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
3470
3471 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3472 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3473 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3474 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3475 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3476 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3477 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3478 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3479
3480 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3481 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3482 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3483 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3484 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3485 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3486 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3487 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3488 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangea1fb292008-08-26 12:58:38 +02003489
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003490 { }
3491};
3492
3493/* Enable GPIO mask and set output */
Kailang Yangbc9f98a2007-04-12 13:06:07 +02003494#define alc880_gpio1_init_verbs alc_gpio1_init_verbs
3495#define alc880_gpio2_init_verbs alc_gpio2_init_verbs
David Heidelberger64a8be72009-06-08 16:15:18 +02003496#define alc880_gpio3_init_verbs alc_gpio3_init_verbs
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003497
Kailang Yangdf694da2005-12-05 19:42:22 +01003498/* Clevo m520g init */
3499static struct hda_verb alc880_pin_clevo_init_verbs[] = {
3500 /* headphone output */
3501 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3502 /* line-out */
3503 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3504 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3505 /* Line-in */
3506 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3507 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3508 /* CD */
3509 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3510 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3511 /* Mic1 (rear panel) */
3512 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3513 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3514 /* Mic2 (front panel) */
3515 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3516 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3517 /* headphone */
3518 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3519 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3520 /* change to EAPD mode */
3521 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3522 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3523
3524 { }
3525};
3526
3527static struct hda_verb alc880_pin_tcl_S700_init_verbs[] = {
Takashi Iwai4b146cb2006-07-28 14:42:36 +02003528 /* change to EAPD mode */
3529 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3530 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3531
Kailang Yangdf694da2005-12-05 19:42:22 +01003532 /* Headphone output */
3533 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3534 /* Front output*/
3535 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3536 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
3537
3538 /* Line In pin widget for input */
3539 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3540 /* CD pin widget for input */
3541 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3542 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3543 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3544
3545 /* change to EAPD mode */
3546 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3547 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
3548
3549 { }
3550};
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003551
3552/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003553 * LG m1 express dual
3554 *
3555 * Pin assignment:
3556 * Rear Line-In/Out (blue): 0x14
3557 * Build-in Mic-In: 0x15
3558 * Speaker-out: 0x17
3559 * HP-Out (green): 0x1b
3560 * Mic-In/Out (red): 0x19
3561 * SPDIF-Out: 0x1e
3562 */
3563
3564/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
3565static hda_nid_t alc880_lg_dac_nids[3] = {
3566 0x05, 0x02, 0x03
3567};
3568
3569/* seems analog CD is not working */
3570static struct hda_input_mux alc880_lg_capture_source = {
3571 .num_items = 3,
3572 .items = {
3573 { "Mic", 0x1 },
3574 { "Line", 0x5 },
3575 { "Internal Mic", 0x6 },
3576 },
3577};
3578
3579/* 2,4,6 channel modes */
3580static struct hda_verb alc880_lg_ch2_init[] = {
3581 /* set line-in and mic-in to input */
3582 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
3583 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3584 { }
3585};
3586
3587static struct hda_verb alc880_lg_ch4_init[] = {
3588 /* set line-in to out and mic-in to input */
3589 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3590 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
3591 { }
3592};
3593
3594static struct hda_verb alc880_lg_ch6_init[] = {
3595 /* set line-in and mic-in to output */
3596 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3597 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
3598 { }
3599};
3600
3601static struct hda_channel_mode alc880_lg_ch_modes[3] = {
3602 { 2, alc880_lg_ch2_init },
3603 { 4, alc880_lg_ch4_init },
3604 { 6, alc880_lg_ch6_init },
3605};
3606
3607static struct snd_kcontrol_new alc880_lg_mixer[] = {
Takashi Iwai2134ea42008-01-10 16:53:55 +01003608 HDA_CODEC_VOLUME("Front Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3609 HDA_BIND_MUTE("Front Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003610 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3611 HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
3612 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
3613 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
3614 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
3615 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
3616 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3617 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
3618 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
3619 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
3620 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
3621 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
3622 {
3623 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3624 .name = "Channel Mode",
3625 .info = alc_ch_mode_info,
3626 .get = alc_ch_mode_get,
3627 .put = alc_ch_mode_put,
3628 },
3629 { } /* end */
3630};
3631
3632static struct hda_verb alc880_lg_init_verbs[] = {
3633 /* set capture source to mic-in */
3634 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3635 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3636 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3637 /* mute all amp mixer inputs */
3638 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003639 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3640 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003641 /* line-in to input */
3642 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3643 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3644 /* built-in mic */
3645 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3646 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3647 /* speaker-out */
3648 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3649 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3650 /* mic-in to input */
3651 {0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
3652 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3653 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3654 /* HP-out */
3655 {0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
3656 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3657 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3658 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003659 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003660 { }
3661};
3662
3663/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003664static void alc880_lg_setup(struct hda_codec *codec)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003665{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003666 struct alc_spec *spec = codec->spec;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003667
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003668 spec->autocfg.hp_pins[0] = 0x1b;
3669 spec->autocfg.speaker_pins[0] = 0x17;
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003670}
3671
3672/*
Takashi Iwaid6815182006-03-23 16:06:23 +01003673 * LG LW20
3674 *
3675 * Pin assignment:
3676 * Speaker-out: 0x14
3677 * Mic-In: 0x18
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003678 * Built-in Mic-In: 0x19
3679 * Line-In: 0x1b
3680 * HP-Out: 0x1a
Takashi Iwaid6815182006-03-23 16:06:23 +01003681 * SPDIF-Out: 0x1e
3682 */
3683
Takashi Iwaid6815182006-03-23 16:06:23 +01003684static struct hda_input_mux alc880_lg_lw_capture_source = {
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003685 .num_items = 3,
Takashi Iwaid6815182006-03-23 16:06:23 +01003686 .items = {
3687 { "Mic", 0x0 },
3688 { "Internal Mic", 0x1 },
Claudio Matsuokae4f41da2007-07-13 11:51:06 +02003689 { "Line In", 0x2 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003690 },
3691};
3692
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003693#define alc880_lg_lw_modes alc880_threestack_modes
3694
Takashi Iwaid6815182006-03-23 16:06:23 +01003695static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003696 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3697 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
3698 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
3699 HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
3700 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
3701 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
3702 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
3703 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
3704 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
3705 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwaid6815182006-03-23 16:06:23 +01003706 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3707 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3708 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
3709 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003710 {
3711 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3712 .name = "Channel Mode",
3713 .info = alc_ch_mode_info,
3714 .get = alc_ch_mode_get,
3715 .put = alc_ch_mode_put,
3716 },
Takashi Iwaid6815182006-03-23 16:06:23 +01003717 { } /* end */
3718};
3719
3720static struct hda_verb alc880_lg_lw_init_verbs[] = {
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02003721 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3722 {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
3723 {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
3724
Takashi Iwaid6815182006-03-23 16:06:23 +01003725 /* set capture source to mic-in */
3726 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3727 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3728 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaicb53c622007-08-10 17:21:45 +02003729 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Takashi Iwaid6815182006-03-23 16:06:23 +01003730 /* speaker-out */
3731 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3732 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3733 /* HP-out */
Takashi Iwaid6815182006-03-23 16:06:23 +01003734 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3735 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3736 /* mic-in to input */
3737 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3738 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3739 /* built-in mic */
3740 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3741 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3742 /* jack sense */
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003743 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaid6815182006-03-23 16:06:23 +01003744 { }
3745};
3746
3747/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003748static void alc880_lg_lw_setup(struct hda_codec *codec)
Takashi Iwaid6815182006-03-23 16:06:23 +01003749{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003750 struct alc_spec *spec = codec->spec;
Takashi Iwaid6815182006-03-23 16:06:23 +01003751
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003752 spec->autocfg.hp_pins[0] = 0x1b;
3753 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwaid6815182006-03-23 16:06:23 +01003754}
3755
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003756static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
3757 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
3758 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
3759 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
3760 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
3761 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
3762 HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
3763 { } /* end */
3764};
3765
3766static struct hda_input_mux alc880_medion_rim_capture_source = {
3767 .num_items = 2,
3768 .items = {
3769 { "Mic", 0x0 },
3770 { "Internal Mic", 0x1 },
3771 },
3772};
3773
3774static struct hda_verb alc880_medion_rim_init_verbs[] = {
3775 {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
3776
3777 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3778 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3779
3780 /* Mic1 (rear panel) pin widget for input and vref at 80% */
3781 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3782 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3783 /* Mic2 (as headphone out) for HP output */
3784 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3785 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3786 /* Internal Speaker */
3787 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3788 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3789
3790 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
3791 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
3792
3793 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
3794 { }
3795};
3796
3797/* toggle speaker-output according to the hp-jack state */
3798static void alc880_medion_rim_automute(struct hda_codec *codec)
3799{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003800 struct alc_spec *spec = codec->spec;
3801 alc_automute_amp(codec);
3802 /* toggle EAPD */
3803 if (spec->jack_present)
Takashi Iwaidf99cd32008-04-25 15:25:04 +02003804 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
3805 else
3806 snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
3807}
3808
3809static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
3810 unsigned int res)
3811{
3812 /* Looks like the unsol event is incompatible with the standard
3813 * definition. 4bit tag is placed at 28 bit!
3814 */
3815 if ((res >> 28) == ALC880_HP_EVENT)
3816 alc880_medion_rim_automute(codec);
3817}
3818
Takashi Iwai4f5d17062009-08-11 18:17:46 +02003819static void alc880_medion_rim_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003820{
3821 struct alc_spec *spec = codec->spec;
3822
3823 spec->autocfg.hp_pins[0] = 0x14;
3824 spec->autocfg.speaker_pins[0] = 0x1b;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02003825}
3826
Takashi Iwaicb53c622007-08-10 17:21:45 +02003827#ifdef CONFIG_SND_HDA_POWER_SAVE
3828static struct hda_amp_list alc880_loopbacks[] = {
3829 { 0x0b, HDA_INPUT, 0 },
3830 { 0x0b, HDA_INPUT, 1 },
3831 { 0x0b, HDA_INPUT, 2 },
3832 { 0x0b, HDA_INPUT, 3 },
3833 { 0x0b, HDA_INPUT, 4 },
3834 { } /* end */
3835};
3836
3837static struct hda_amp_list alc880_lg_loopbacks[] = {
3838 { 0x0b, HDA_INPUT, 1 },
3839 { 0x0b, HDA_INPUT, 6 },
3840 { 0x0b, HDA_INPUT, 7 },
3841 { } /* end */
3842};
3843#endif
3844
Takashi Iwaid6815182006-03-23 16:06:23 +01003845/*
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003846 * Common callbacks
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003847 */
Takashi Iwai16ded522005-06-10 19:58:24 +02003848
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849static int alc_init(struct hda_codec *codec)
3850{
3851 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003852 unsigned int i;
3853
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003854 alc_fix_pll(codec);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02003855 alc_auto_init_amp(codec, spec->init_amp);
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +02003856
Takashi Iwaie9edcee2005-06-13 14:16:38 +02003857 for (i = 0; i < spec->num_init_verbs; i++)
3858 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003859
3860 if (spec->init_hook)
3861 spec->init_hook(codec);
3862
Takashi Iwai9e5341b2010-09-21 09:57:06 +02003863 hda_call_check_power_status(codec, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 return 0;
3865}
3866
Takashi Iwaiae6b8132006-03-03 16:47:17 +01003867static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
3868{
3869 struct alc_spec *spec = codec->spec;
3870
3871 if (spec->unsol_event)
3872 spec->unsol_event(codec, res);
3873}
3874
Takashi Iwaicb53c622007-08-10 17:21:45 +02003875#ifdef CONFIG_SND_HDA_POWER_SAVE
3876static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
3877{
3878 struct alc_spec *spec = codec->spec;
3879 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
3880}
3881#endif
3882
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883/*
3884 * Analog playback callbacks
3885 */
3886static int alc880_playback_pcm_open(struct hda_pcm_stream *hinfo,
3887 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003888 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889{
3890 struct alc_spec *spec = codec->spec;
Takashi Iwai9a081602008-02-12 18:37:26 +01003891 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
3892 hinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893}
3894
3895static int alc880_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3896 struct hda_codec *codec,
3897 unsigned int stream_tag,
3898 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003899 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900{
3901 struct alc_spec *spec = codec->spec;
Takashi Iwai9c7f8522006-06-28 15:08:22 +02003902 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
3903 stream_tag, format, substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904}
3905
3906static int alc880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3907 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003908 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909{
3910 struct alc_spec *spec = codec->spec;
3911 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
3912}
3913
3914/*
3915 * Digital out
3916 */
3917static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
3918 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003919 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920{
3921 struct alc_spec *spec = codec->spec;
3922 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
3923}
3924
Takashi Iwai6b97eb42007-04-05 14:51:48 +02003925static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
3926 struct hda_codec *codec,
3927 unsigned int stream_tag,
3928 unsigned int format,
3929 struct snd_pcm_substream *substream)
3930{
3931 struct alc_spec *spec = codec->spec;
3932 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
3933 stream_tag, format, substream);
3934}
3935
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01003936static int alc880_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
3937 struct hda_codec *codec,
3938 struct snd_pcm_substream *substream)
3939{
3940 struct alc_spec *spec = codec->spec;
3941 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
3942}
3943
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
3945 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003946 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947{
3948 struct alc_spec *spec = codec->spec;
3949 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
3950}
3951
3952/*
3953 * Analog capture
3954 */
Takashi Iwai63300792008-01-24 15:31:36 +01003955static int alc880_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 struct hda_codec *codec,
3957 unsigned int stream_tag,
3958 unsigned int format,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003959 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960{
3961 struct alc_spec *spec = codec->spec;
3962
Takashi Iwai63300792008-01-24 15:31:36 +01003963 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 stream_tag, 0, format);
3965 return 0;
3966}
3967
Takashi Iwai63300792008-01-24 15:31:36 +01003968static int alc880_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 struct hda_codec *codec,
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01003970 struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971{
3972 struct alc_spec *spec = codec->spec;
3973
Takashi Iwai888afa12008-03-18 09:57:50 +01003974 snd_hda_codec_cleanup_stream(codec,
3975 spec->adc_nids[substream->number + 1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 return 0;
3977}
3978
Takashi Iwai840b64c2010-07-13 22:49:01 +02003979/* analog capture with dynamic dual-adc changes */
3980static int dualmic_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3981 struct hda_codec *codec,
3982 unsigned int stream_tag,
3983 unsigned int format,
3984 struct snd_pcm_substream *substream)
3985{
3986 struct alc_spec *spec = codec->spec;
3987 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
3988 spec->cur_adc_stream_tag = stream_tag;
3989 spec->cur_adc_format = format;
3990 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
3991 return 0;
3992}
3993
3994static int dualmic_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3995 struct hda_codec *codec,
3996 struct snd_pcm_substream *substream)
3997{
3998 struct alc_spec *spec = codec->spec;
3999 snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
4000 spec->cur_adc = 0;
4001 return 0;
4002}
4003
4004static struct hda_pcm_stream dualmic_pcm_analog_capture = {
4005 .substreams = 1,
4006 .channels_min = 2,
4007 .channels_max = 2,
4008 .nid = 0, /* fill later */
4009 .ops = {
4010 .prepare = dualmic_capture_pcm_prepare,
4011 .cleanup = dualmic_capture_pcm_cleanup
4012 },
4013};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
4015/*
4016 */
4017static struct hda_pcm_stream alc880_pcm_analog_playback = {
4018 .substreams = 1,
4019 .channels_min = 2,
4020 .channels_max = 8,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004021 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 .ops = {
4023 .open = alc880_playback_pcm_open,
4024 .prepare = alc880_playback_pcm_prepare,
4025 .cleanup = alc880_playback_pcm_cleanup
4026 },
4027};
4028
4029static struct hda_pcm_stream alc880_pcm_analog_capture = {
Takashi Iwai63300792008-01-24 15:31:36 +01004030 .substreams = 1,
4031 .channels_min = 2,
4032 .channels_max = 2,
4033 /* NID is set in alc_build_pcms */
4034};
4035
4036static struct hda_pcm_stream alc880_pcm_analog_alt_playback = {
4037 .substreams = 1,
4038 .channels_min = 2,
4039 .channels_max = 2,
4040 /* NID is set in alc_build_pcms */
4041};
4042
4043static struct hda_pcm_stream alc880_pcm_analog_alt_capture = {
4044 .substreams = 2, /* can be overridden */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 .channels_min = 2,
4046 .channels_max = 2,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004047 /* NID is set in alc_build_pcms */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 .ops = {
Takashi Iwai63300792008-01-24 15:31:36 +01004049 .prepare = alc880_alt_capture_pcm_prepare,
4050 .cleanup = alc880_alt_capture_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 },
4052};
4053
4054static struct hda_pcm_stream alc880_pcm_digital_playback = {
4055 .substreams = 1,
4056 .channels_min = 2,
4057 .channels_max = 2,
4058 /* NID is set in alc_build_pcms */
4059 .ops = {
4060 .open = alc880_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +02004061 .close = alc880_dig_playback_pcm_close,
Takashi Iwai9b5f12e2009-02-13 11:47:37 +01004062 .prepare = alc880_dig_playback_pcm_prepare,
4063 .cleanup = alc880_dig_playback_pcm_cleanup
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064 },
4065};
4066
4067static struct hda_pcm_stream alc880_pcm_digital_capture = {
4068 .substreams = 1,
4069 .channels_min = 2,
4070 .channels_max = 2,
4071 /* NID is set in alc_build_pcms */
4072};
4073
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004074/* Used by alc_build_pcms to flag that a PCM has no playback stream */
Takashi Iwai63300792008-01-24 15:31:36 +01004075static struct hda_pcm_stream alc_pcm_null_stream = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01004076 .substreams = 0,
4077 .channels_min = 0,
4078 .channels_max = 0,
4079};
4080
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081static int alc_build_pcms(struct hda_codec *codec)
4082{
4083 struct alc_spec *spec = codec->spec;
4084 struct hda_pcm *info = spec->pcm_rec;
4085 int i;
4086
4087 codec->num_pcms = 1;
4088 codec->pcm_info = info;
4089
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004090 if (spec->no_analog)
4091 goto skip_analog;
4092
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004093 snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
4094 "%s Analog", codec->chip_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 info->name = spec->stream_name_analog;
Kailang Yang274693f2009-12-03 10:07:50 +01004096
Takashi Iwai4a471b72005-12-07 13:56:29 +01004097 if (spec->stream_analog_playback) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004098 if (snd_BUG_ON(!spec->multiout.dac_nids))
4099 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004100 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback);
4101 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
4102 }
4103 if (spec->stream_analog_capture) {
Takashi Iwaida3cec32008-08-08 17:12:14 +02004104 if (snd_BUG_ON(!spec->adc_nids))
4105 return -EINVAL;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004106 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
4107 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
4108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109
Takashi Iwai4a471b72005-12-07 13:56:29 +01004110 if (spec->channel_mode) {
4111 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
4112 for (i = 0; i < spec->num_channel_mode; i++) {
4113 if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
4114 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
4115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 }
4117 }
4118
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004119 skip_analog:
Takashi Iwaie08a0072006-09-07 17:52:14 +02004120 /* SPDIF for stream index #1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
Takashi Iwai812a2cc2009-05-16 10:00:49 +02004122 snprintf(spec->stream_name_digital,
4123 sizeof(spec->stream_name_digital),
4124 "%s Digital", codec->chip_name);
Takashi Iwaie08a0072006-09-07 17:52:14 +02004125 codec->num_pcms = 2;
Wu Fengguangb25c9da2009-02-06 15:02:27 +08004126 codec->slave_dig_outs = spec->multiout.slave_dig_outs;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004127 info = spec->pcm_rec + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 info->name = spec->stream_name_digital;
Takashi Iwai8c441982009-01-20 18:30:20 +01004129 if (spec->dig_out_type)
4130 info->pcm_type = spec->dig_out_type;
4131 else
4132 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a471b72005-12-07 13:56:29 +01004133 if (spec->multiout.dig_out_nid &&
4134 spec->stream_digital_playback) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_digital_playback);
4136 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
4137 }
Takashi Iwai4a471b72005-12-07 13:56:29 +01004138 if (spec->dig_in_nid &&
4139 spec->stream_digital_capture) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_digital_capture);
4141 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
4142 }
Takashi Iwai963f8032008-08-11 10:04:40 +02004143 /* FIXME: do we need this for all Realtek codec models? */
4144 codec->spdif_status_reset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 }
4146
Takashi Iwaie64f14f2009-01-20 18:32:55 +01004147 if (spec->no_analog)
4148 return 0;
4149
Takashi Iwaie08a0072006-09-07 17:52:14 +02004150 /* If the use of more than one ADC is requested for the current
4151 * model, configure a second analog capture-only PCM.
4152 */
4153 /* Additional Analaog capture for index #2 */
Takashi Iwai63300792008-01-24 15:31:36 +01004154 if ((spec->alt_dac_nid && spec->stream_analog_alt_playback) ||
4155 (spec->num_adc_nids > 1 && spec->stream_analog_alt_capture)) {
Takashi Iwaie08a0072006-09-07 17:52:14 +02004156 codec->num_pcms = 3;
Takashi Iwaic06134d2006-10-11 18:49:13 +02004157 info = spec->pcm_rec + 2;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004158 info->name = spec->stream_name_analog;
Takashi Iwai63300792008-01-24 15:31:36 +01004159 if (spec->alt_dac_nid) {
4160 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4161 *spec->stream_analog_alt_playback;
4162 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
4163 spec->alt_dac_nid;
4164 } else {
4165 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
4166 alc_pcm_null_stream;
4167 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
4168 }
4169 if (spec->num_adc_nids > 1) {
4170 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4171 *spec->stream_analog_alt_capture;
4172 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
4173 spec->adc_nids[1];
4174 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
4175 spec->num_adc_nids - 1;
4176 } else {
4177 info->stream[SNDRV_PCM_STREAM_CAPTURE] =
4178 alc_pcm_null_stream;
4179 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
Takashi Iwaie08a0072006-09-07 17:52:14 +02004180 }
4181 }
4182
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 return 0;
4184}
4185
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004186static inline void alc_shutup(struct hda_codec *codec)
4187{
4188 snd_hda_shutup_pins(codec);
4189}
4190
Takashi Iwai603c4012008-07-30 15:01:44 +02004191static void alc_free_kctls(struct hda_codec *codec)
4192{
4193 struct alc_spec *spec = codec->spec;
4194
4195 if (spec->kctls.list) {
4196 struct snd_kcontrol_new *kctl = spec->kctls.list;
4197 int i;
4198 for (i = 0; i < spec->kctls.used; i++)
4199 kfree(kctl[i].name);
4200 }
4201 snd_array_free(&spec->kctls);
4202}
4203
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204static void alc_free(struct hda_codec *codec)
4205{
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004206 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004207
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004208 if (!spec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004209 return;
4210
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004211 alc_shutup(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +02004212 alc_free_kctls(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004213 kfree(spec);
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09004214 snd_hda_detach_beep_device(codec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215}
4216
Hector Martinf5de24b2009-12-20 22:51:31 +01004217#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -05004218static void alc_power_eapd(struct hda_codec *codec)
4219{
4220 /* We currently only handle front, HP */
4221 switch (codec->vendor_id) {
4222 case 0x10ec0260:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004223 set_eapd(codec, 0x0f, 0);
4224 set_eapd(codec, 0x10, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004225 break;
4226 case 0x10ec0262:
4227 case 0x10ec0267:
4228 case 0x10ec0268:
4229 case 0x10ec0269:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004230 case 0x10ec0270:
Daniel T Chenc97259d2009-12-27 18:52:08 -05004231 case 0x10ec0272:
4232 case 0x10ec0660:
4233 case 0x10ec0662:
4234 case 0x10ec0663:
4235 case 0x10ec0862:
4236 case 0x10ec0889:
Takashi Iwai9e4c8492010-01-19 15:53:43 +01004237 set_eapd(codec, 0x14, 0);
4238 set_eapd(codec, 0x15, 0);
Daniel T Chenc97259d2009-12-27 18:52:08 -05004239 break;
4240 }
4241}
4242
Hector Martinf5de24b2009-12-20 22:51:31 +01004243static int alc_suspend(struct hda_codec *codec, pm_message_t state)
4244{
4245 struct alc_spec *spec = codec->spec;
Takashi Iwaia4e09aa2009-12-27 11:22:24 +01004246 alc_shutup(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004247 if (spec && spec->power_hook)
Daniel T Chenc97259d2009-12-27 18:52:08 -05004248 spec->power_hook(codec);
Hector Martinf5de24b2009-12-20 22:51:31 +01004249 return 0;
4250}
4251#endif
4252
Takashi Iwaie044c392008-10-27 16:56:24 +01004253#ifdef SND_HDA_NEEDS_RESUME
Takashi Iwaie044c392008-10-27 16:56:24 +01004254static int alc_resume(struct hda_codec *codec)
4255{
Takashi Iwaie044c392008-10-27 16:56:24 +01004256 codec->patch_ops.init(codec);
4257 snd_hda_codec_resume_amp(codec);
4258 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +02004259 hda_call_check_power_status(codec, 0x01);
Takashi Iwaie044c392008-10-27 16:56:24 +01004260 return 0;
4261}
Takashi Iwaie044c392008-10-27 16:56:24 +01004262#endif
4263
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264/*
4265 */
4266static struct hda_codec_ops alc_patch_ops = {
4267 .build_controls = alc_build_controls,
4268 .build_pcms = alc_build_pcms,
4269 .init = alc_init,
4270 .free = alc_free,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004271 .unsol_event = alc_unsol_event,
Takashi Iwaie044c392008-10-27 16:56:24 +01004272#ifdef SND_HDA_NEEDS_RESUME
4273 .resume = alc_resume,
4274#endif
Takashi Iwaicb53c622007-08-10 17:21:45 +02004275#ifdef CONFIG_SND_HDA_POWER_SAVE
Hector Martinf5de24b2009-12-20 22:51:31 +01004276 .suspend = alc_suspend,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004277 .check_power_status = alc_check_power_status,
4278#endif
Daniel T Chenc97259d2009-12-27 18:52:08 -05004279 .reboot_notify = alc_shutup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280};
4281
Kailang Yangc027ddc2010-03-19 11:33:06 +01004282/* replace the codec chip_name with the given string */
4283static int alc_codec_rename(struct hda_codec *codec, const char *name)
4284{
4285 kfree(codec->chip_name);
4286 codec->chip_name = kstrdup(name, GFP_KERNEL);
4287 if (!codec->chip_name) {
4288 alc_free(codec);
4289 return -ENOMEM;
4290 }
4291 return 0;
4292}
4293
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004294/*
4295 * Test configuration for debugging
4296 *
4297 * Almost all inputs/outputs are enabled. I/O pins can be configured via
4298 * enum controls.
4299 */
4300#ifdef CONFIG_SND_DEBUG
4301static hda_nid_t alc880_test_dac_nids[4] = {
4302 0x02, 0x03, 0x04, 0x05
4303};
4304
4305static struct hda_input_mux alc880_test_capture_source = {
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004306 .num_items = 7,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004307 .items = {
4308 { "In-1", 0x0 },
4309 { "In-2", 0x1 },
4310 { "In-3", 0x2 },
4311 { "In-4", 0x3 },
4312 { "CD", 0x4 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004313 { "Front", 0x5 },
4314 { "Surround", 0x6 },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004315 },
4316};
4317
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01004318static struct hda_channel_mode alc880_test_modes[4] = {
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004319 { 2, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004320 { 4, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004321 { 6, NULL },
Takashi Iwaifd2c3262005-05-13 17:18:42 +02004322 { 8, NULL },
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004323};
4324
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004325static int alc_test_pin_ctl_info(struct snd_kcontrol *kcontrol,
4326 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004327{
4328 static char *texts[] = {
4329 "N/A", "Line Out", "HP Out",
4330 "In Hi-Z", "In 50%", "In Grd", "In 80%", "In 100%"
4331 };
4332 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4333 uinfo->count = 1;
4334 uinfo->value.enumerated.items = 8;
4335 if (uinfo->value.enumerated.item >= 8)
4336 uinfo->value.enumerated.item = 7;
4337 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4338 return 0;
4339}
4340
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004341static int alc_test_pin_ctl_get(struct snd_kcontrol *kcontrol,
4342 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004343{
4344 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4345 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4346 unsigned int pin_ctl, item = 0;
4347
4348 pin_ctl = snd_hda_codec_read(codec, nid, 0,
4349 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4350 if (pin_ctl & AC_PINCTL_OUT_EN) {
4351 if (pin_ctl & AC_PINCTL_HP_EN)
4352 item = 2;
4353 else
4354 item = 1;
4355 } else if (pin_ctl & AC_PINCTL_IN_EN) {
4356 switch (pin_ctl & AC_PINCTL_VREFEN) {
4357 case AC_PINCTL_VREF_HIZ: item = 3; break;
4358 case AC_PINCTL_VREF_50: item = 4; break;
4359 case AC_PINCTL_VREF_GRD: item = 5; break;
4360 case AC_PINCTL_VREF_80: item = 6; break;
4361 case AC_PINCTL_VREF_100: item = 7; break;
4362 }
4363 }
4364 ucontrol->value.enumerated.item[0] = item;
4365 return 0;
4366}
4367
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004368static int alc_test_pin_ctl_put(struct snd_kcontrol *kcontrol,
4369 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004370{
4371 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4372 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4373 static unsigned int ctls[] = {
4374 0, AC_PINCTL_OUT_EN, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN,
4375 AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ,
4376 AC_PINCTL_IN_EN | AC_PINCTL_VREF_50,
4377 AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD,
4378 AC_PINCTL_IN_EN | AC_PINCTL_VREF_80,
4379 AC_PINCTL_IN_EN | AC_PINCTL_VREF_100,
4380 };
4381 unsigned int old_ctl, new_ctl;
4382
4383 old_ctl = snd_hda_codec_read(codec, nid, 0,
4384 AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
4385 new_ctl = ctls[ucontrol->value.enumerated.item[0]];
4386 if (old_ctl != new_ctl) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004387 int val;
4388 snd_hda_codec_write_cache(codec, nid, 0,
4389 AC_VERB_SET_PIN_WIDGET_CONTROL,
4390 new_ctl);
Takashi Iwai47fd8302007-08-10 17:11:07 +02004391 val = ucontrol->value.enumerated.item[0] >= 3 ?
4392 HDA_AMP_MUTE : 0;
4393 snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
4394 HDA_AMP_MUTE, val);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004395 return 1;
4396 }
4397 return 0;
4398}
4399
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004400static int alc_test_pin_src_info(struct snd_kcontrol *kcontrol,
4401 struct snd_ctl_elem_info *uinfo)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004402{
4403 static char *texts[] = {
4404 "Front", "Surround", "CLFE", "Side"
4405 };
4406 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
4407 uinfo->count = 1;
4408 uinfo->value.enumerated.items = 4;
4409 if (uinfo->value.enumerated.item >= 4)
4410 uinfo->value.enumerated.item = 3;
4411 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
4412 return 0;
4413}
4414
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004415static int alc_test_pin_src_get(struct snd_kcontrol *kcontrol,
4416 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004417{
4418 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4419 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4420 unsigned int sel;
4421
4422 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0);
4423 ucontrol->value.enumerated.item[0] = sel & 3;
4424 return 0;
4425}
4426
Takashi Iwai9c7f8522006-06-28 15:08:22 +02004427static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol,
4428 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004429{
4430 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4431 hda_nid_t nid = (hda_nid_t)kcontrol->private_value;
4432 unsigned int sel;
4433
4434 sel = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONNECT_SEL, 0) & 3;
4435 if (ucontrol->value.enumerated.item[0] != sel) {
4436 sel = ucontrol->value.enumerated.item[0] & 3;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02004437 snd_hda_codec_write_cache(codec, nid, 0,
4438 AC_VERB_SET_CONNECT_SEL, sel);
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004439 return 1;
4440 }
4441 return 0;
4442}
4443
4444#define PIN_CTL_TEST(xname,nid) { \
4445 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4446 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004447 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004448 .info = alc_test_pin_ctl_info, \
4449 .get = alc_test_pin_ctl_get, \
4450 .put = alc_test_pin_ctl_put, \
4451 .private_value = nid \
4452 }
4453
4454#define PIN_SRC_TEST(xname,nid) { \
4455 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
4456 .name = xname, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01004457 .subdevice = HDA_SUBDEV_NID_FLAG | nid, \
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004458 .info = alc_test_pin_src_info, \
4459 .get = alc_test_pin_src_get, \
4460 .put = alc_test_pin_src_put, \
4461 .private_value = nid \
4462 }
4463
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004464static struct snd_kcontrol_new alc880_test_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02004465 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
4466 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
4467 HDA_CODEC_VOLUME("CLFE Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
4468 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01004469 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
4470 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
4471 HDA_BIND_MUTE("CLFE Playback Switch", 0x0e, 2, HDA_INPUT),
4472 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004473 PIN_CTL_TEST("Front Pin Mode", 0x14),
4474 PIN_CTL_TEST("Surround Pin Mode", 0x15),
4475 PIN_CTL_TEST("CLFE Pin Mode", 0x16),
4476 PIN_CTL_TEST("Side Pin Mode", 0x17),
4477 PIN_CTL_TEST("In-1 Pin Mode", 0x18),
4478 PIN_CTL_TEST("In-2 Pin Mode", 0x19),
4479 PIN_CTL_TEST("In-3 Pin Mode", 0x1a),
4480 PIN_CTL_TEST("In-4 Pin Mode", 0x1b),
4481 PIN_SRC_TEST("In-1 Pin Source", 0x18),
4482 PIN_SRC_TEST("In-2 Pin Source", 0x19),
4483 PIN_SRC_TEST("In-3 Pin Source", 0x1a),
4484 PIN_SRC_TEST("In-4 Pin Source", 0x1b),
4485 HDA_CODEC_VOLUME("In-1 Playback Volume", 0x0b, 0x0, HDA_INPUT),
4486 HDA_CODEC_MUTE("In-1 Playback Switch", 0x0b, 0x0, HDA_INPUT),
4487 HDA_CODEC_VOLUME("In-2 Playback Volume", 0x0b, 0x1, HDA_INPUT),
4488 HDA_CODEC_MUTE("In-2 Playback Switch", 0x0b, 0x1, HDA_INPUT),
4489 HDA_CODEC_VOLUME("In-3 Playback Volume", 0x0b, 0x2, HDA_INPUT),
4490 HDA_CODEC_MUTE("In-3 Playback Switch", 0x0b, 0x2, HDA_INPUT),
4491 HDA_CODEC_VOLUME("In-4 Playback Volume", 0x0b, 0x3, HDA_INPUT),
4492 HDA_CODEC_MUTE("In-4 Playback Switch", 0x0b, 0x3, HDA_INPUT),
4493 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x4, HDA_INPUT),
4494 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x4, HDA_INPUT),
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004495 {
4496 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4497 .name = "Channel Mode",
Kailang Yangdf694da2005-12-05 19:42:22 +01004498 .info = alc_ch_mode_info,
4499 .get = alc_ch_mode_get,
4500 .put = alc_ch_mode_put,
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004501 },
4502 { } /* end */
4503};
4504
4505static struct hda_verb alc880_test_init_verbs[] = {
4506 /* Unmute inputs of 0x0c - 0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004507 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4508 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4509 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4510 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4512 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4513 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4514 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004515 /* Vol output for 0x0c-0x0f */
Takashi Iwai05acb862005-06-10 19:50:25 +02004516 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4517 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4518 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4519 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004520 /* Set output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004521 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4522 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4523 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4524 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004525 /* Unmute output pins 0x14-0x17 */
Takashi Iwai05acb862005-06-10 19:50:25 +02004526 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4527 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4528 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4529 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004530 /* Set input pins 0x18-0x1c */
Takashi Iwai16ded522005-06-10 19:58:24 +02004531 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4532 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai05acb862005-06-10 19:50:25 +02004533 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4534 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4535 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004536 /* Mute input pins 0x18-0x1b */
Takashi Iwai05acb862005-06-10 19:50:25 +02004537 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4538 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4539 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4540 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004541 /* ADC set up */
Takashi Iwai05acb862005-06-10 19:50:25 +02004542 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004543 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004544 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004545 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004546 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02004547 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02004548 /* Analog input/passthru */
4549 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4550 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4551 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4552 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4553 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004554 { }
4555};
4556#endif
4557
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558/*
4559 */
4560
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004561static const char *alc880_models[ALC880_MODEL_LAST] = {
4562 [ALC880_3ST] = "3stack",
4563 [ALC880_TCL_S700] = "tcl",
4564 [ALC880_3ST_DIG] = "3stack-digout",
4565 [ALC880_CLEVO] = "clevo",
4566 [ALC880_5ST] = "5stack",
4567 [ALC880_5ST_DIG] = "5stack-digout",
4568 [ALC880_W810] = "w810",
4569 [ALC880_Z71V] = "z71v",
4570 [ALC880_6ST] = "6stack",
4571 [ALC880_6ST_DIG] = "6stack-digout",
4572 [ALC880_ASUS] = "asus",
4573 [ALC880_ASUS_W1V] = "asus-w1v",
4574 [ALC880_ASUS_DIG] = "asus-dig",
4575 [ALC880_ASUS_DIG2] = "asus-dig2",
4576 [ALC880_UNIWILL_DIG] = "uniwill",
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004577 [ALC880_UNIWILL_P53] = "uniwill-p53",
4578 [ALC880_FUJITSU] = "fujitsu",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004579 [ALC880_F1734] = "F1734",
4580 [ALC880_LG] = "lg",
4581 [ALC880_LG_LW] = "lg-lw",
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004582 [ALC880_MEDION_RIM] = "medion",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004583#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004584 [ALC880_TEST] = "test",
Takashi Iwai2fa522b2005-05-12 14:51:12 +02004585#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004586 [ALC880_AUTO] = "auto",
4587};
4588
4589static struct snd_pci_quirk alc880_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004590 SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_W810),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004591 SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_5ST_DIG),
4592 SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_6ST),
4593 SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_3ST_DIG),
4594 SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_6ST_DIG),
4595 SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_6ST_DIG),
4596 SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_6ST_DIG),
4597 SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_3ST_DIG),
4598 SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004599 SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_6ST_DIG),
4600 SND_PCI_QUIRK(0x103c, 0x2a09, "HP", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004601 SND_PCI_QUIRK(0x1043, 0x10b3, "ASUS W1V", ALC880_ASUS_W1V),
4602 SND_PCI_QUIRK(0x1043, 0x10c2, "ASUS W6A", ALC880_ASUS_DIG),
4603 SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS Wxx", ALC880_ASUS_DIG),
4604 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS", ALC880_ASUS_DIG),
4605 SND_PCI_QUIRK(0x1043, 0x1123, "ASUS", ALC880_ASUS_DIG),
4606 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS", ALC880_ASUS_DIG),
4607 SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_Z71V),
4608 /* SND_PCI_QUIRK(0x1043, 0x1964, "ASUS", ALC880_ASUS_DIG), */
4609 SND_PCI_QUIRK(0x1043, 0x1973, "ASUS", ALC880_ASUS_DIG),
4610 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS", ALC880_ASUS_DIG),
Travis Place186c3112008-05-20 11:54:41 +02004611 SND_PCI_QUIRK(0x1043, 0x814e, "ASUS P5GD1 w/SPDIF", ALC880_6ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004612 SND_PCI_QUIRK(0x1043, 0x8181, "ASUS P4GPL", ALC880_ASUS_DIG),
4613 SND_PCI_QUIRK(0x1043, 0x8196, "ASUS P5GD1", ALC880_6ST),
4614 SND_PCI_QUIRK(0x1043, 0x81b4, "ASUS", ALC880_6ST),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004615 SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_ASUS), /* default ASUS */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004616 SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004617 SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_3ST),
4618 SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004619 SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_5ST),
4620 SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_5ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004621 SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_6ST_DIG),
4622 SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_6ST_DIG),
4623 SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_6ST_DIG),
4624 SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004625 SND_PCI_QUIRK(0x1558, 0x0520, "Clevo m520G", ALC880_CLEVO),
4626 SND_PCI_QUIRK(0x1558, 0x0660, "Clevo m655n", ALC880_CLEVO),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004627 SND_PCI_QUIRK(0x1558, 0x5401, "ASUS", ALC880_ASUS_DIG2),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004628 SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004629 SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_UNIWILL_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004630 SND_PCI_QUIRK(0x1584, 0x9054, "Uniwlll", ALC880_F1734),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004631 SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
4632 SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004633 SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004634 SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004635 SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004636 SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004637 SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
Travis Place1d116042008-06-23 11:42:30 +02004638 SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU),
Daniel T Chen33535412010-04-22 07:15:26 -04004639 SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004640 SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004641 SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004642 SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
Daniel T Chen77c4d5c2010-12-02 22:45:45 -05004643 SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004644 SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004645 SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004646 SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
4647 SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_6ST_DIG), /* broken BIOS */
4648 SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_6ST_DIG),
4649 SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004650 SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_5ST_DIG),
4651 SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004652 SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004653 SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004654 SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_3ST_DIG),
4655 SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_3ST_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01004656 SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_5ST_DIG),
4657 SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_5ST_DIG),
4658 SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_5ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +01004659 /* default Intel */
4660 SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01004661 SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_5ST_DIG),
4662 SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_6ST_DIG),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 {}
4664};
4665
Takashi Iwai16ded522005-06-10 19:58:24 +02004666/*
Kailang Yangdf694da2005-12-05 19:42:22 +01004667 * ALC880 codec presets
Takashi Iwai16ded522005-06-10 19:58:24 +02004668 */
Takashi Iwai16ded522005-06-10 19:58:24 +02004669static struct alc_config_preset alc880_presets[] = {
4670 [ALC880_3ST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004671 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004672 .init_verbs = { alc880_volume_init_verbs,
4673 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004674 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004675 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004676 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4677 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004678 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004679 .input_mux = &alc880_capture_source,
4680 },
4681 [ALC880_3ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004682 .mixers = { alc880_three_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004683 .init_verbs = { alc880_volume_init_verbs,
4684 alc880_pin_3stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004685 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwai16ded522005-06-10 19:58:24 +02004686 .dac_nids = alc880_dac_nids,
4687 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004688 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4689 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004690 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004691 .input_mux = &alc880_capture_source,
4692 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004693 [ALC880_TCL_S700] = {
4694 .mixers = { alc880_tcl_s700_mixer },
4695 .init_verbs = { alc880_volume_init_verbs,
4696 alc880_pin_tcl_S700_init_verbs,
4697 alc880_gpio2_init_verbs },
4698 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4699 .dac_nids = alc880_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01004700 .adc_nids = alc880_adc_nids_alt, /* FIXME: correct? */
4701 .num_adc_nids = 1, /* single ADC */
Kailang Yangdf694da2005-12-05 19:42:22 +01004702 .hp_nid = 0x03,
4703 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4704 .channel_mode = alc880_2_jack_modes,
4705 .input_mux = &alc880_capture_source,
4706 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004707 [ALC880_5ST] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004708 .mixers = { alc880_three_stack_mixer,
4709 alc880_five_stack_mixer},
4710 .init_verbs = { alc880_volume_init_verbs,
4711 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004712 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4713 .dac_nids = alc880_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004714 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4715 .channel_mode = alc880_fivestack_modes,
4716 .input_mux = &alc880_capture_source,
4717 },
4718 [ALC880_5ST_DIG] = {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004719 .mixers = { alc880_three_stack_mixer,
4720 alc880_five_stack_mixer },
4721 .init_verbs = { alc880_volume_init_verbs,
4722 alc880_pin_5stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004723 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4724 .dac_nids = alc880_dac_nids,
4725 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004726 .num_channel_mode = ARRAY_SIZE(alc880_fivestack_modes),
4727 .channel_mode = alc880_fivestack_modes,
4728 .input_mux = &alc880_capture_source,
4729 },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004730 [ALC880_6ST] = {
4731 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004732 .init_verbs = { alc880_volume_init_verbs,
4733 alc880_pin_6stack_init_verbs },
Takashi Iwaib6482d42005-06-27 15:32:43 +02004734 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4735 .dac_nids = alc880_6st_dac_nids,
4736 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4737 .channel_mode = alc880_sixstack_modes,
4738 .input_mux = &alc880_6stack_capture_source,
4739 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004740 [ALC880_6ST_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004741 .mixers = { alc880_six_stack_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004742 .init_verbs = { alc880_volume_init_verbs,
4743 alc880_pin_6stack_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004744 .num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
4745 .dac_nids = alc880_6st_dac_nids,
4746 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004747 .num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
4748 .channel_mode = alc880_sixstack_modes,
4749 .input_mux = &alc880_6stack_capture_source,
4750 },
4751 [ALC880_W810] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004752 .mixers = { alc880_w810_base_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004753 .init_verbs = { alc880_volume_init_verbs,
4754 alc880_pin_w810_init_verbs,
Takashi Iwaib0af0de2005-06-21 14:49:19 +02004755 alc880_gpio2_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004756 .num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
4757 .dac_nids = alc880_w810_dac_nids,
4758 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004759 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
4760 .channel_mode = alc880_w810_modes,
4761 .input_mux = &alc880_capture_source,
4762 },
4763 [ALC880_Z71V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004764 .mixers = { alc880_z71v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004765 .init_verbs = { alc880_volume_init_verbs,
4766 alc880_pin_z71v_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004767 .num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
4768 .dac_nids = alc880_z71v_dac_nids,
4769 .dig_out_nid = ALC880_DIGOUT_NID,
4770 .hp_nid = 0x03,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004771 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4772 .channel_mode = alc880_2_jack_modes,
Takashi Iwai16ded522005-06-10 19:58:24 +02004773 .input_mux = &alc880_capture_source,
4774 },
4775 [ALC880_F1734] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004776 .mixers = { alc880_f1734_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004777 .init_verbs = { alc880_volume_init_verbs,
4778 alc880_pin_f1734_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004779 .num_dacs = ARRAY_SIZE(alc880_f1734_dac_nids),
4780 .dac_nids = alc880_f1734_dac_nids,
4781 .hp_nid = 0x02,
4782 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4783 .channel_mode = alc880_2_jack_modes,
Takashi Iwai937b4162008-02-11 14:52:36 +01004784 .input_mux = &alc880_f1734_capture_source,
4785 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004786 .setup = alc880_uniwill_p53_setup,
4787 .init_hook = alc_automute_amp,
Takashi Iwai16ded522005-06-10 19:58:24 +02004788 },
4789 [ALC880_ASUS] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004790 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004791 .init_verbs = { alc880_volume_init_verbs,
4792 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004793 alc880_gpio1_init_verbs },
4794 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4795 .dac_nids = alc880_asus_dac_nids,
4796 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4797 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004798 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004799 .input_mux = &alc880_capture_source,
4800 },
4801 [ALC880_ASUS_DIG] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004802 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004803 .init_verbs = { alc880_volume_init_verbs,
4804 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004805 alc880_gpio1_init_verbs },
4806 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4807 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004808 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004809 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4810 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004811 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004812 .input_mux = &alc880_capture_source,
4813 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004814 [ALC880_ASUS_DIG2] = {
4815 .mixers = { alc880_asus_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004816 .init_verbs = { alc880_volume_init_verbs,
4817 alc880_pin_asus_init_verbs,
Kailang Yangdf694da2005-12-05 19:42:22 +01004818 alc880_gpio2_init_verbs }, /* use GPIO2 */
4819 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4820 .dac_nids = alc880_asus_dac_nids,
4821 .dig_out_nid = ALC880_DIGOUT_NID,
4822 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4823 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004824 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004825 .input_mux = &alc880_capture_source,
4826 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004827 [ALC880_ASUS_W1V] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004828 .mixers = { alc880_asus_mixer, alc880_asus_w1v_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004829 .init_verbs = { alc880_volume_init_verbs,
4830 alc880_pin_asus_init_verbs,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004831 alc880_gpio1_init_verbs },
4832 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4833 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004834 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004835 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4836 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004837 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004838 .input_mux = &alc880_capture_source,
4839 },
4840 [ALC880_UNIWILL_DIG] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004841 .mixers = { alc880_asus_mixer },
Kailang Yangccc656c2006-10-17 12:32:26 +02004842 .init_verbs = { alc880_volume_init_verbs,
4843 alc880_pin_asus_init_verbs },
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004844 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4845 .dac_nids = alc880_asus_dac_nids,
Takashi Iwai16ded522005-06-10 19:58:24 +02004846 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004847 .num_channel_mode = ARRAY_SIZE(alc880_asus_modes),
4848 .channel_mode = alc880_asus_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004849 .need_dac_fix = 1,
Takashi Iwai16ded522005-06-10 19:58:24 +02004850 .input_mux = &alc880_capture_source,
4851 },
Kailang Yangccc656c2006-10-17 12:32:26 +02004852 [ALC880_UNIWILL] = {
4853 .mixers = { alc880_uniwill_mixer },
4854 .init_verbs = { alc880_volume_init_verbs,
4855 alc880_uniwill_init_verbs },
4856 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4857 .dac_nids = alc880_asus_dac_nids,
4858 .dig_out_nid = ALC880_DIGOUT_NID,
4859 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4860 .channel_mode = alc880_threestack_modes,
4861 .need_dac_fix = 1,
4862 .input_mux = &alc880_capture_source,
4863 .unsol_event = alc880_uniwill_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004864 .setup = alc880_uniwill_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004865 .init_hook = alc880_uniwill_init_hook,
Kailang Yangccc656c2006-10-17 12:32:26 +02004866 },
4867 [ALC880_UNIWILL_P53] = {
4868 .mixers = { alc880_uniwill_p53_mixer },
4869 .init_verbs = { alc880_volume_init_verbs,
4870 alc880_uniwill_p53_init_verbs },
4871 .num_dacs = ARRAY_SIZE(alc880_asus_dac_nids),
4872 .dac_nids = alc880_asus_dac_nids,
4873 .num_channel_mode = ARRAY_SIZE(alc880_w810_modes),
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004874 .channel_mode = alc880_threestack_modes,
4875 .input_mux = &alc880_capture_source,
4876 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004877 .setup = alc880_uniwill_p53_setup,
4878 .init_hook = alc_automute_amp,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004879 },
4880 [ALC880_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01004881 .mixers = { alc880_fujitsu_mixer },
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004882 .init_verbs = { alc880_volume_init_verbs,
4883 alc880_uniwill_p53_init_verbs,
4884 alc880_beep_init_verbs },
4885 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4886 .dac_nids = alc880_dac_nids,
Takashi Iwaid53d7d92007-08-20 15:20:02 +02004887 .dig_out_nid = ALC880_DIGOUT_NID,
Tobin Davis2cf9f0f2007-02-07 16:04:25 +01004888 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4889 .channel_mode = alc880_2_jack_modes,
Kailang Yangccc656c2006-10-17 12:32:26 +02004890 .input_mux = &alc880_capture_source,
4891 .unsol_event = alc880_uniwill_p53_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004892 .setup = alc880_uniwill_p53_setup,
4893 .init_hook = alc_automute_amp,
Kailang Yangccc656c2006-10-17 12:32:26 +02004894 },
Kailang Yangdf694da2005-12-05 19:42:22 +01004895 [ALC880_CLEVO] = {
4896 .mixers = { alc880_three_stack_mixer },
4897 .init_verbs = { alc880_volume_init_verbs,
4898 alc880_pin_clevo_init_verbs },
4899 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4900 .dac_nids = alc880_dac_nids,
4901 .hp_nid = 0x03,
4902 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
4903 .channel_mode = alc880_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004904 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +01004905 .input_mux = &alc880_capture_source,
4906 },
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004907 [ALC880_LG] = {
4908 .mixers = { alc880_lg_mixer },
4909 .init_verbs = { alc880_volume_init_verbs,
4910 alc880_lg_init_verbs },
4911 .num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
4912 .dac_nids = alc880_lg_dac_nids,
4913 .dig_out_nid = ALC880_DIGOUT_NID,
4914 .num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
4915 .channel_mode = alc880_lg_ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +02004916 .need_dac_fix = 1,
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004917 .input_mux = &alc880_lg_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004918 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004919 .setup = alc880_lg_setup,
4920 .init_hook = alc_automute_amp,
Takashi Iwaicb53c622007-08-10 17:21:45 +02004921#ifdef CONFIG_SND_HDA_POWER_SAVE
4922 .loopbacks = alc880_lg_loopbacks,
4923#endif
Takashi Iwaiae6b8132006-03-03 16:47:17 +01004924 },
Takashi Iwaid6815182006-03-23 16:06:23 +01004925 [ALC880_LG_LW] = {
4926 .mixers = { alc880_lg_lw_mixer },
4927 .init_verbs = { alc880_volume_init_verbs,
4928 alc880_lg_lw_init_verbs },
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004929 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
Takashi Iwaid6815182006-03-23 16:06:23 +01004930 .dac_nids = alc880_dac_nids,
4931 .dig_out_nid = ALC880_DIGOUT_NID,
Claudio Matsuoka0a8c5da2007-07-04 15:17:38 +02004932 .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
4933 .channel_mode = alc880_lg_lw_modes,
Takashi Iwaid6815182006-03-23 16:06:23 +01004934 .input_mux = &alc880_lg_lw_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02004935 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004936 .setup = alc880_lg_lw_setup,
4937 .init_hook = alc_automute_amp,
Takashi Iwaid6815182006-03-23 16:06:23 +01004938 },
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004939 [ALC880_MEDION_RIM] = {
4940 .mixers = { alc880_medion_rim_mixer },
4941 .init_verbs = { alc880_volume_init_verbs,
4942 alc880_medion_rim_init_verbs,
4943 alc_gpio2_init_verbs },
4944 .num_dacs = ARRAY_SIZE(alc880_dac_nids),
4945 .dac_nids = alc880_dac_nids,
4946 .dig_out_nid = ALC880_DIGOUT_NID,
4947 .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
4948 .channel_mode = alc880_2_jack_modes,
4949 .input_mux = &alc880_medion_rim_capture_source,
4950 .unsol_event = alc880_medion_rim_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02004951 .setup = alc880_medion_rim_setup,
4952 .init_hook = alc880_medion_rim_automute,
Takashi Iwaidf99cd32008-04-25 15:25:04 +02004953 },
Takashi Iwai16ded522005-06-10 19:58:24 +02004954#ifdef CONFIG_SND_DEBUG
4955 [ALC880_TEST] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004956 .mixers = { alc880_test_mixer },
4957 .init_verbs = { alc880_test_init_verbs },
Takashi Iwai16ded522005-06-10 19:58:24 +02004958 .num_dacs = ARRAY_SIZE(alc880_test_dac_nids),
4959 .dac_nids = alc880_test_dac_nids,
4960 .dig_out_nid = ALC880_DIGOUT_NID,
Takashi Iwai16ded522005-06-10 19:58:24 +02004961 .num_channel_mode = ARRAY_SIZE(alc880_test_modes),
4962 .channel_mode = alc880_test_modes,
4963 .input_mux = &alc880_test_capture_source,
4964 },
4965#endif
4966};
4967
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004968/*
4969 * Automatic parse of I/O pins from the BIOS configuration
4970 */
4971
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004972enum {
4973 ALC_CTL_WIDGET_VOL,
4974 ALC_CTL_WIDGET_MUTE,
4975 ALC_CTL_BIND_MUTE,
4976};
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004977static struct snd_kcontrol_new alc880_control_templates[] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004978 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
4979 HDA_CODEC_MUTE(NULL, 0, 0, 0),
Takashi Iwai985be542005-11-02 18:26:49 +01004980 HDA_BIND_MUTE(NULL, 0, 0, 0),
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004981};
4982
4983/* add dynamic controls */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004984static int add_control(struct alc_spec *spec, int type, const char *name,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004985 int cidx, unsigned long val)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004986{
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01004987 struct snd_kcontrol_new *knew;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004988
Takashi Iwai603c4012008-07-30 15:01:44 +02004989 snd_array_init(&spec->kctls, sizeof(*knew), 32);
4990 knew = snd_array_new(&spec->kctls);
4991 if (!knew)
4992 return -ENOMEM;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004993 *knew = alc880_control_templates[type];
Paulo Marques543537b2005-06-23 00:09:02 -07004994 knew->name = kstrdup(name, GFP_KERNEL);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02004995 if (!knew->name)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02004996 return -ENOMEM;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02004997 knew->index = cidx;
Jaroslav Kysela4d02d1b2009-11-12 10:15:48 +01004998 if (get_amp_nid_(val))
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004999 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005000 knew->private_value = val;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005001 return 0;
5002}
5003
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005004static int add_control_with_pfx(struct alc_spec *spec, int type,
5005 const char *pfx, const char *dir,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005006 const char *sfx, int cidx, unsigned long val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005007{
5008 char name[32];
5009 snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005010 return add_control(spec, type, name, cidx, val);
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005011}
5012
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005013#define add_pb_vol_ctrl(spec, type, pfx, val) \
5014 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
5015#define add_pb_sw_ctrl(spec, type, pfx, val) \
5016 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
5017#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \
5018 add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
5019#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \
5020 add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005021
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005022#define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17)
5023#define alc880_fixed_pin_idx(nid) ((nid) - 0x14)
5024#define alc880_is_multi_pin(nid) ((nid) >= 0x18)
5025#define alc880_multi_pin_idx(nid) ((nid) - 0x18)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005026#define alc880_idx_to_dac(nid) ((nid) + 0x02)
5027#define alc880_dac_to_idx(nid) ((nid) - 0x02)
5028#define alc880_idx_to_mixer(nid) ((nid) + 0x0c)
5029#define alc880_idx_to_selector(nid) ((nid) + 0x10)
5030#define ALC880_PIN_CD_NID 0x1c
5031
5032/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005033static int alc880_auto_fill_dac_nids(struct alc_spec *spec,
5034 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005035{
5036 hda_nid_t nid;
5037 int assigned[4];
5038 int i, j;
5039
5040 memset(assigned, 0, sizeof(assigned));
Takashi Iwaib0af0de2005-06-21 14:49:19 +02005041 spec->multiout.dac_nids = spec->private_dac_nids;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005042
5043 /* check the pins hardwired to audio widget */
5044 for (i = 0; i < cfg->line_outs; i++) {
5045 nid = cfg->line_out_pins[i];
5046 if (alc880_is_fixed_pin(nid)) {
5047 int idx = alc880_fixed_pin_idx(nid);
Libin Yang5014f192005-11-23 15:48:36 +01005048 spec->multiout.dac_nids[i] = alc880_idx_to_dac(idx);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005049 assigned[idx] = 1;
5050 }
5051 }
5052 /* left pins can be connect to any audio widget */
5053 for (i = 0; i < cfg->line_outs; i++) {
5054 nid = cfg->line_out_pins[i];
5055 if (alc880_is_fixed_pin(nid))
5056 continue;
5057 /* search for an empty channel */
5058 for (j = 0; j < cfg->line_outs; j++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005059 if (!assigned[j]) {
5060 spec->multiout.dac_nids[i] =
5061 alc880_idx_to_dac(j);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005062 assigned[j] = 1;
5063 break;
5064 }
5065 }
5066 }
5067 spec->multiout.num_dacs = cfg->line_outs;
5068 return 0;
5069}
5070
5071/* add playback controls from the parsed DAC table */
Kailang Yangdf694da2005-12-05 19:42:22 +01005072static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec,
5073 const struct auto_pin_cfg *cfg)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005074{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005075 static const char *chname[4] = {
5076 "Front", "Surround", NULL /*CLFE*/, "Side"
5077 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005078 hda_nid_t nid;
5079 int i, err;
5080
5081 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005082 if (!spec->multiout.dac_nids[i])
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005083 continue;
5084 nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i]));
5085 if (i == 2) {
5086 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005087 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5088 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005089 HDA_COMPOSE_AMP_VAL(nid, 1, 0,
5090 HDA_OUTPUT));
5091 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005092 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005093 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
5094 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005095 HDA_COMPOSE_AMP_VAL(nid, 2, 0,
5096 HDA_OUTPUT));
5097 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005098 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005099 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5100 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005101 HDA_COMPOSE_AMP_VAL(nid, 1, 2,
5102 HDA_INPUT));
5103 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005104 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005105 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
5106 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005107 HDA_COMPOSE_AMP_VAL(nid, 2, 2,
5108 HDA_INPUT));
5109 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005110 return err;
5111 } else {
Takashi Iwaicb162b62009-08-25 16:05:03 +02005112 const char *pfx;
5113 if (cfg->line_outs == 1 &&
5114 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
5115 pfx = "Speaker";
5116 else
5117 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005118 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005119 HDA_COMPOSE_AMP_VAL(nid, 3, 0,
5120 HDA_OUTPUT));
5121 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005122 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005123 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005124 HDA_COMPOSE_AMP_VAL(nid, 3, 2,
5125 HDA_INPUT));
5126 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005127 return err;
5128 }
5129 }
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005130 return 0;
5131}
5132
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005133/* add playback controls for speaker and HP outputs */
5134static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin,
5135 const char *pfx)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005136{
5137 hda_nid_t nid;
5138 int err;
5139
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005140 if (!pin)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005141 return 0;
5142
5143 if (alc880_is_fixed_pin(pin)) {
5144 nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
Takashi Iwai82bc9552006-03-21 11:24:42 +01005145 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005146 if (!spec->multiout.hp_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005147 spec->multiout.hp_nid = nid;
Takashi Iwai82bc9552006-03-21 11:24:42 +01005148 else
5149 spec->multiout.extra_out_nid[0] = nid;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005150 /* control HP volume/switch on the output mixer amp */
5151 nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005152 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005153 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
5154 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005155 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005156 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005157 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
5158 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005159 return err;
5160 } else if (alc880_is_multi_pin(pin)) {
5161 /* set manual connection */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005162 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02005163 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005164 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
5165 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005166 return err;
5167 }
5168 return 0;
5169}
5170
5171/* create input playback/capture controls for the given pin */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005172static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005173 const char *ctlname, int ctlidx,
Kailang Yangdf694da2005-12-05 19:42:22 +01005174 int idx, hda_nid_t mix_nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005175{
Kailang Yangdf694da2005-12-05 19:42:22 +01005176 int err;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005177
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005178 err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005179 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5180 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005181 return err;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005182 err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005183 HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
5184 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005185 return err;
5186 return 0;
5187}
5188
Takashi Iwai05f5f472009-08-25 13:10:18 +02005189static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005190{
Takashi Iwai05f5f472009-08-25 13:10:18 +02005191 unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
5192 return (pincap & AC_PINCAP_IN) != 0;
5193}
5194
5195/* create playback/capture controls for input pins */
5196static int alc_auto_create_input_ctls(struct hda_codec *codec,
5197 const struct auto_pin_cfg *cfg,
5198 hda_nid_t mixer,
5199 hda_nid_t cap1, hda_nid_t cap2)
5200{
5201 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005202 struct hda_input_mux *imux = &spec->private_imux[0];
David Henningsson5322bf22011-01-05 11:03:56 +01005203 int i, err, idx, type_idx = 0;
5204 const char *prev_label = NULL;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005205
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005206 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai05f5f472009-08-25 13:10:18 +02005207 hda_nid_t pin;
Takashi Iwai10a20af2010-09-09 16:28:02 +02005208 const char *label;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005209
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005210 pin = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005211 if (!alc_is_input_pin(codec, pin))
5212 continue;
5213
David Henningsson5322bf22011-01-05 11:03:56 +01005214 label = hda_get_autocfg_input_label(codec, cfg, i);
5215 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005216 type_idx++;
5217 else
5218 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +01005219 prev_label = label;
5220
Takashi Iwai05f5f472009-08-25 13:10:18 +02005221 if (mixer) {
5222 idx = get_connection_index(codec, mixer, pin);
5223 if (idx >= 0) {
5224 err = new_analog_input(spec, pin,
Takashi Iwai10a20af2010-09-09 16:28:02 +02005225 label, type_idx,
5226 idx, mixer);
Takashi Iwai05f5f472009-08-25 13:10:18 +02005227 if (err < 0)
5228 return err;
5229 }
5230 }
5231
5232 if (!cap1)
5233 continue;
5234 idx = get_connection_index(codec, cap1, pin);
5235 if (idx < 0 && cap2)
5236 idx = get_connection_index(codec, cap2, pin);
Takashi Iwai10a20af2010-09-09 16:28:02 +02005237 if (idx >= 0)
5238 snd_hda_add_imux_item(imux, label, idx, NULL);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005239 }
5240 return 0;
5241}
5242
Takashi Iwai05f5f472009-08-25 13:10:18 +02005243static int alc880_auto_create_input_ctls(struct hda_codec *codec,
5244 const struct auto_pin_cfg *cfg)
5245{
5246 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x08, 0x09);
5247}
5248
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005249static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
5250 unsigned int pin_type)
5251{
5252 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
5253 pin_type);
5254 /* unmute pin */
Takashi Iwaid260cdf2008-02-13 17:19:35 +01005255 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
5256 AMP_OUT_UNMUTE);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005257}
5258
Kailang Yangdf694da2005-12-05 19:42:22 +01005259static void alc880_auto_set_output_and_unmute(struct hda_codec *codec,
5260 hda_nid_t nid, int pin_type,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005261 int dac_idx)
5262{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005263 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005264 /* need the manual connection? */
5265 if (alc880_is_multi_pin(nid)) {
5266 struct alc_spec *spec = codec->spec;
5267 int idx = alc880_multi_pin_idx(nid);
5268 snd_hda_codec_write(codec, alc880_idx_to_selector(idx), 0,
5269 AC_VERB_SET_CONNECT_SEL,
5270 alc880_dac_to_idx(spec->multiout.dac_nids[dac_idx]));
5271 }
5272}
5273
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005274static int get_pin_type(int line_out_type)
5275{
5276 if (line_out_type == AUTO_PIN_HP_OUT)
5277 return PIN_HP;
5278 else
5279 return PIN_OUT;
5280}
5281
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005282static void alc880_auto_init_multi_out(struct hda_codec *codec)
5283{
5284 struct alc_spec *spec = codec->spec;
5285 int i;
Kailang Yangea1fb292008-08-26 12:58:38 +02005286
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005287 for (i = 0; i < spec->autocfg.line_outs; i++) {
5288 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02005289 int pin_type = get_pin_type(spec->autocfg.line_out_type);
5290 alc880_auto_set_output_and_unmute(codec, nid, pin_type, i);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005291 }
5292}
5293
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005294static void alc880_auto_init_extra_out(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005295{
5296 struct alc_spec *spec = codec->spec;
5297 hda_nid_t pin;
5298
Takashi Iwai82bc9552006-03-21 11:24:42 +01005299 pin = spec->autocfg.speaker_pins[0];
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005300 if (pin) /* connect to front */
5301 alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Takashi Iwaieb06ed82006-09-20 17:10:27 +02005302 pin = spec->autocfg.hp_pins[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005303 if (pin) /* connect to front */
5304 alc880_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
5305}
5306
5307static void alc880_auto_init_analog_input(struct hda_codec *codec)
5308{
5309 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005310 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005311 int i;
5312
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005313 for (i = 0; i < cfg->num_inputs; i++) {
5314 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005315 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02005316 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01005317 if (nid != ALC880_PIN_CD_NID &&
5318 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005319 snd_hda_codec_write(codec, nid, 0,
5320 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005321 AMP_OUT_MUTE);
5322 }
5323 }
5324}
5325
Takashi Iwai7f311a42010-04-09 17:32:23 +02005326static void alc880_auto_init_input_src(struct hda_codec *codec)
5327{
5328 struct alc_spec *spec = codec->spec;
5329 int c;
5330
5331 for (c = 0; c < spec->num_adc_nids; c++) {
5332 unsigned int mux_idx;
5333 const struct hda_input_mux *imux;
5334 mux_idx = c >= spec->num_mux_defs ? 0 : c;
5335 imux = &spec->input_mux[mux_idx];
5336 if (!imux->num_items && mux_idx > 0)
5337 imux = &spec->input_mux[0];
5338 if (imux)
5339 snd_hda_codec_write(codec, spec->adc_nids[c], 0,
5340 AC_VERB_SET_CONNECT_SEL,
5341 imux->items[0].index);
5342 }
5343}
5344
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005345/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005346/* return 1 if successful, 0 if the proper config is not found,
5347 * or a negative error code
5348 */
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005349static int alc880_parse_auto_config(struct hda_codec *codec)
5350{
5351 struct alc_spec *spec = codec->spec;
Takashi Iwai757899a2010-07-30 10:48:14 +02005352 int err;
Kailang Yangdf694da2005-12-05 19:42:22 +01005353 static hda_nid_t alc880_ignore[] = { 0x1d, 0 };
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005354
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005355 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
5356 alc880_ignore);
5357 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005358 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005359 if (!spec->autocfg.line_outs)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005360 return 0; /* can't find valid BIOS pin config */
Kailang Yangdf694da2005-12-05 19:42:22 +01005361
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005362 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
5363 if (err < 0)
5364 return err;
5365 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
5366 if (err < 0)
5367 return err;
5368 err = alc880_auto_create_extra_out(spec,
5369 spec->autocfg.speaker_pins[0],
5370 "Speaker");
5371 if (err < 0)
5372 return err;
5373 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
5374 "Headphone");
5375 if (err < 0)
5376 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +02005377 err = alc880_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005378 if (err < 0)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005379 return err;
5380
5381 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
5382
Takashi Iwai757899a2010-07-30 10:48:14 +02005383 alc_auto_parse_digital(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005384
Takashi Iwai603c4012008-07-30 15:01:44 +02005385 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01005386 add_mixer(spec, spec->kctls.list);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005387
Takashi Iwaid88897e2008-10-31 15:01:37 +01005388 add_verb(spec, alc880_volume_init_verbs);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005389
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005390 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02005391 spec->input_mux = &spec->private_imux[0];
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005392
Kailang Yang6227cdc2010-02-25 08:36:52 +01005393 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02005394
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005395 return 1;
5396}
5397
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005398/* additional initialization for auto-configuration model */
5399static void alc880_auto_init(struct hda_codec *codec)
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005400{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005401 struct alc_spec *spec = codec->spec;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005402 alc880_auto_init_multi_out(codec);
Takashi Iwai8d88bc32005-11-17 11:09:23 +01005403 alc880_auto_init_extra_out(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005404 alc880_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02005405 alc880_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02005406 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01005407 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02005408 alc_inithook(codec);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005409}
5410
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005411/* check the ADC/MUX contains all input pins; some ADC/MUX contains only
5412 * one of two digital mic pins, e.g. on ALC272
5413 */
5414static void fixup_automic_adc(struct hda_codec *codec)
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005415{
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005416 struct alc_spec *spec = codec->spec;
5417 int i;
5418
5419 for (i = 0; i < spec->num_adc_nids; i++) {
5420 hda_nid_t cap = spec->capsrc_nids ?
5421 spec->capsrc_nids[i] : spec->adc_nids[i];
5422 int iidx, eidx;
5423
5424 iidx = get_connection_index(codec, cap, spec->int_mic.pin);
5425 if (iidx < 0)
5426 continue;
5427 eidx = get_connection_index(codec, cap, spec->ext_mic.pin);
5428 if (eidx < 0)
5429 continue;
5430 spec->int_mic.mux_idx = iidx;
5431 spec->ext_mic.mux_idx = eidx;
5432 if (spec->capsrc_nids)
5433 spec->capsrc_nids += i;
5434 spec->adc_nids += i;
5435 spec->num_adc_nids = 1;
5436 return;
5437 }
5438 snd_printd(KERN_INFO "hda_codec: %s: "
5439 "No ADC/MUX containing both 0x%x and 0x%x pins\n",
5440 codec->chip_name, spec->int_mic.pin, spec->ext_mic.pin);
5441 spec->auto_mic = 0; /* disable auto-mic to be sure */
5442}
5443
Takashi Iwai748cce42010-08-04 07:37:39 +02005444/* select or unmute the given capsrc route */
5445static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
5446 int idx)
5447{
5448 if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
5449 snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
5450 HDA_AMP_MUTE, 0);
5451 } else {
5452 snd_hda_codec_write_cache(codec, cap, 0,
5453 AC_VERB_SET_CONNECT_SEL, idx);
5454 }
5455}
5456
Takashi Iwai840b64c2010-07-13 22:49:01 +02005457/* set the default connection to that pin */
5458static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
5459{
5460 struct alc_spec *spec = codec->spec;
5461 int i;
5462
5463 for (i = 0; i < spec->num_adc_nids; i++) {
5464 hda_nid_t cap = spec->capsrc_nids ?
5465 spec->capsrc_nids[i] : spec->adc_nids[i];
5466 int idx;
5467
5468 idx = get_connection_index(codec, cap, pin);
5469 if (idx < 0)
5470 continue;
Takashi Iwai748cce42010-08-04 07:37:39 +02005471 select_or_unmute_capsrc(codec, cap, idx);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005472 return i; /* return the found index */
5473 }
5474 return -1; /* not found */
5475}
5476
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005477/* choose the ADC/MUX containing the input pin and initialize the setup */
5478static void fixup_single_adc(struct hda_codec *codec)
5479{
5480 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005481 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005482 int i;
5483
5484 /* search for the input pin; there must be only one */
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005485 if (cfg->num_inputs != 1)
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005486 return;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005487 i = init_capsrc_for_pin(codec, cfg->inputs[0].pin);
Takashi Iwai840b64c2010-07-13 22:49:01 +02005488 if (i >= 0) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005489 /* use only this ADC */
5490 if (spec->capsrc_nids)
5491 spec->capsrc_nids += i;
5492 spec->adc_nids += i;
5493 spec->num_adc_nids = 1;
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005494 }
5495}
5496
Takashi Iwai840b64c2010-07-13 22:49:01 +02005497/* initialize dual adcs */
5498static void fixup_dual_adc_switch(struct hda_codec *codec)
5499{
5500 struct alc_spec *spec = codec->spec;
5501 init_capsrc_for_pin(codec, spec->ext_mic.pin);
5502 init_capsrc_for_pin(codec, spec->int_mic.pin);
5503}
5504
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005505static void set_capture_mixer(struct hda_codec *codec)
5506{
5507 struct alc_spec *spec = codec->spec;
Takashi Iwaia23b6882009-03-23 15:21:36 +01005508 static struct snd_kcontrol_new *caps[2][3] = {
5509 { alc_capture_mixer_nosrc1,
5510 alc_capture_mixer_nosrc2,
5511 alc_capture_mixer_nosrc3 },
5512 { alc_capture_mixer1,
5513 alc_capture_mixer2,
5514 alc_capture_mixer3 },
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005515 };
Takashi Iwaia23b6882009-03-23 15:21:36 +01005516 if (spec->num_adc_nids > 0 && spec->num_adc_nids <= 3) {
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005517 int mux = 0;
Takashi Iwai840b64c2010-07-13 22:49:01 +02005518 int num_adcs = spec->num_adc_nids;
5519 if (spec->dual_adc_switch)
5520 fixup_dual_adc_switch(codec);
5521 else if (spec->auto_mic)
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005522 fixup_automic_adc(codec);
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +01005523 else if (spec->input_mux) {
5524 if (spec->input_mux->num_items > 1)
5525 mux = 1;
5526 else if (spec->input_mux->num_items == 1)
5527 fixup_single_adc(codec);
5528 }
Takashi Iwai840b64c2010-07-13 22:49:01 +02005529 if (spec->dual_adc_switch)
5530 num_adcs = 1;
5531 spec->cap_mixer = caps[mux][num_adcs - 1];
Takashi Iwaia23b6882009-03-23 15:21:36 +01005532 }
Takashi Iwaif9e336f2008-10-31 16:37:07 +01005533}
5534
Takashi Iwai66946352010-03-29 17:21:45 +02005535/* fill adc_nids (and capsrc_nids) containing all active input pins */
5536static void fillup_priv_adc_nids(struct hda_codec *codec, hda_nid_t *nids,
5537 int num_nids)
5538{
5539 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005540 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai66946352010-03-29 17:21:45 +02005541 int n;
5542 hda_nid_t fallback_adc = 0, fallback_cap = 0;
5543
5544 for (n = 0; n < num_nids; n++) {
5545 hda_nid_t adc, cap;
5546 hda_nid_t conn[HDA_MAX_NUM_INPUTS];
5547 int nconns, i, j;
5548
5549 adc = nids[n];
5550 if (get_wcaps_type(get_wcaps(codec, adc)) != AC_WID_AUD_IN)
5551 continue;
5552 cap = adc;
5553 nconns = snd_hda_get_connections(codec, cap, conn,
5554 ARRAY_SIZE(conn));
5555 if (nconns == 1) {
5556 cap = conn[0];
5557 nconns = snd_hda_get_connections(codec, cap, conn,
5558 ARRAY_SIZE(conn));
5559 }
5560 if (nconns <= 0)
5561 continue;
5562 if (!fallback_adc) {
5563 fallback_adc = adc;
5564 fallback_cap = cap;
5565 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005566 for (i = 0; i < cfg->num_inputs; i++) {
5567 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai66946352010-03-29 17:21:45 +02005568 for (j = 0; j < nconns; j++) {
5569 if (conn[j] == nid)
5570 break;
5571 }
5572 if (j >= nconns)
5573 break;
5574 }
Takashi Iwai66ceeb62010-08-30 13:05:52 +02005575 if (i >= cfg->num_inputs) {
Takashi Iwai66946352010-03-29 17:21:45 +02005576 int num_adcs = spec->num_adc_nids;
5577 spec->private_adc_nids[num_adcs] = adc;
5578 spec->private_capsrc_nids[num_adcs] = cap;
5579 spec->num_adc_nids++;
5580 spec->adc_nids = spec->private_adc_nids;
5581 if (adc != cap)
5582 spec->capsrc_nids = spec->private_capsrc_nids;
5583 }
5584 }
5585 if (!spec->num_adc_nids) {
5586 printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
Takashi Iwai1f85d722010-03-30 07:48:05 +02005587 " using fallback 0x%x\n",
5588 codec->chip_name, fallback_adc);
Takashi Iwai66946352010-03-29 17:21:45 +02005589 spec->private_adc_nids[0] = fallback_adc;
5590 spec->adc_nids = spec->private_adc_nids;
5591 if (fallback_adc != fallback_cap) {
5592 spec->private_capsrc_nids[0] = fallback_cap;
5593 spec->capsrc_nids = spec->private_adc_nids;
5594 }
5595 }
5596}
5597
Takashi Iwai67d634c2009-11-16 15:35:59 +01005598#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005599#define set_beep_amp(spec, nid, idx, dir) \
5600 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005601
5602static struct snd_pci_quirk beep_white_list[] = {
5603 SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
Takashi Iwai080dc7b2010-09-08 08:38:41 +02005604 SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
Takashi Iwaie096c8e2010-08-03 17:20:35 +02005605 SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005606 {}
5607};
5608
5609static inline int has_cdefine_beep(struct hda_codec *codec)
5610{
5611 struct alc_spec *spec = codec->spec;
5612 const struct snd_pci_quirk *q;
5613 q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
5614 if (q)
5615 return q->value;
5616 return spec->cdefine.enable_pcbeep;
5617}
Takashi Iwai67d634c2009-11-16 15:35:59 +01005618#else
5619#define set_beep_amp(spec, nid, idx, dir) /* NOP */
Takashi Iwaidc1eae22010-07-29 15:30:02 +02005620#define has_cdefine_beep(codec) 0
Takashi Iwai67d634c2009-11-16 15:35:59 +01005621#endif
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005622
5623/*
5624 * OK, here we have finally the patch for ALC880
5625 */
5626
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627static int patch_alc880(struct hda_codec *codec)
5628{
5629 struct alc_spec *spec;
5630 int board_config;
Kailang Yangdf694da2005-12-05 19:42:22 +01005631 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632
Takashi Iwaie560d8d2005-09-09 14:21:46 +02005633 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 if (spec == NULL)
5635 return -ENOMEM;
5636
5637 codec->spec = spec;
5638
Takashi Iwaif5fcc132006-11-24 17:07:44 +01005639 board_config = snd_hda_check_board_config(codec, ALC880_MODEL_LAST,
5640 alc880_models,
5641 alc880_cfg_tbl);
5642 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02005643 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5644 codec->chip_name);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005645 board_config = ALC880_AUTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 }
5647
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005648 if (board_config == ALC880_AUTO) {
5649 /* automatic parse from the BIOS config */
5650 err = alc880_parse_auto_config(codec);
5651 if (err < 0) {
5652 alc_free(codec);
5653 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005654 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02005655 printk(KERN_INFO
5656 "hda_codec: Cannot set up configuration "
5657 "from BIOS. Using 3-stack mode...\n");
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005658 board_config = ALC880_3ST;
5659 }
5660 }
5661
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09005662 err = snd_hda_attach_beep_device(codec, 0x1);
5663 if (err < 0) {
5664 alc_free(codec);
5665 return err;
5666 }
5667
Kailang Yangdf694da2005-12-05 19:42:22 +01005668 if (board_config != ALC880_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02005669 setup_preset(codec, &alc880_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 spec->stream_analog_playback = &alc880_pcm_analog_playback;
5672 spec->stream_analog_capture = &alc880_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +01005673 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 spec->stream_digital_playback = &alc880_pcm_digital_playback;
5676 spec->stream_digital_capture = &alc880_pcm_digital_capture;
5677
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005678 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005679 /* check whether NID 0x07 is valid */
Takashi Iwai54d17402005-11-21 16:33:22 +01005680 unsigned int wcap = get_wcaps(codec, alc880_adc_nids[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005681 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +02005682 wcap = get_wcaps_type(wcap);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005683 if (wcap != AC_WID_AUD_IN) {
5684 spec->adc_nids = alc880_adc_nids_alt;
5685 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids_alt);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005686 } else {
5687 spec->adc_nids = alc880_adc_nids;
5688 spec->num_adc_nids = ARRAY_SIZE(alc880_adc_nids);
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005689 }
5690 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02005691 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01005692 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693
Takashi Iwai2134ea42008-01-10 16:53:55 +01005694 spec->vmaster_nid = 0x0c;
5695
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 codec->patch_ops = alc_patch_ops;
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005697 if (board_config == ALC880_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01005698 spec->init_hook = alc880_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02005699#ifdef CONFIG_SND_HDA_POWER_SAVE
5700 if (!spec->loopback.amplist)
5701 spec->loopback.amplist = alc880_loopbacks;
5702#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
5704 return 0;
5705}
5706
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005707
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708/*
5709 * ALC260 support
5710 */
5711
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005712static hda_nid_t alc260_dac_nids[1] = {
5713 /* front */
5714 0x02,
5715};
5716
5717static hda_nid_t alc260_adc_nids[1] = {
5718 /* ADC0 */
5719 0x04,
5720};
5721
Kailang Yangdf694da2005-12-05 19:42:22 +01005722static hda_nid_t alc260_adc_nids_alt[1] = {
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005723 /* ADC1 */
5724 0x05,
5725};
5726
Jonathan Woithed57fdac2006-02-28 11:38:35 +01005727/* NIDs used when simultaneous access to both ADCs makes sense. Note that
5728 * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
5729 */
5730static hda_nid_t alc260_dual_adc_nids[2] = {
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01005731 /* ADC0, ADC1 */
5732 0x04, 0x05
5733};
5734
Takashi Iwaie9edcee2005-06-13 14:16:38 +02005735#define ALC260_DIGOUT_NID 0x03
5736#define ALC260_DIGIN_NID 0x06
5737
5738static struct hda_input_mux alc260_capture_source = {
5739 .num_items = 4,
5740 .items = {
5741 { "Mic", 0x0 },
5742 { "Front Mic", 0x1 },
5743 { "Line", 0x2 },
5744 { "CD", 0x4 },
5745 },
5746};
5747
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01005748/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005749 * headphone jack and the internal CD lines since these are the only pins at
5750 * which audio can appear. For flexibility, also allow the option of
5751 * recording the mixer output on the second ADC (ADC0 doesn't have a
5752 * connection to the mixer output).
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005753 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005754static struct hda_input_mux alc260_fujitsu_capture_sources[2] = {
5755 {
5756 .num_items = 3,
5757 .items = {
5758 { "Mic/Line", 0x0 },
5759 { "CD", 0x4 },
5760 { "Headphone", 0x2 },
5761 },
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005762 },
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005763 {
5764 .num_items = 4,
5765 .items = {
5766 { "Mic/Line", 0x0 },
5767 { "CD", 0x4 },
5768 { "Headphone", 0x2 },
5769 { "Mixer", 0x5 },
5770 },
5771 },
5772
Jonathan Woithea9430dd2005-09-16 19:12:48 +02005773};
5774
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005775/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configuration to
5776 * the Fujitsu S702x, but jacks are marked differently.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005777 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02005778static struct hda_input_mux alc260_acer_capture_sources[2] = {
5779 {
5780 .num_items = 4,
5781 .items = {
5782 { "Mic", 0x0 },
5783 { "Line", 0x2 },
5784 { "CD", 0x4 },
5785 { "Headphone", 0x5 },
5786 },
5787 },
5788 {
5789 .num_items = 5,
5790 .items = {
5791 { "Mic", 0x0 },
5792 { "Line", 0x2 },
5793 { "CD", 0x4 },
5794 { "Headphone", 0x6 },
5795 { "Mixer", 0x5 },
5796 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005797 },
5798};
Michael Schwingencc959482009-02-22 18:58:45 +01005799
5800/* Maxdata Favorit 100XS */
5801static struct hda_input_mux alc260_favorit100_capture_sources[2] = {
5802 {
5803 .num_items = 2,
5804 .items = {
5805 { "Line/Mic", 0x0 },
5806 { "CD", 0x4 },
5807 },
5808 },
5809 {
5810 .num_items = 3,
5811 .items = {
5812 { "Line/Mic", 0x0 },
5813 { "CD", 0x4 },
5814 { "Mixer", 0x5 },
5815 },
5816 },
5817};
5818
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819/*
5820 * This is just place-holder, so there's something for alc_build_pcms to look
5821 * at when it calculates the maximum number of channels. ALC260 has no mixer
5822 * element which allows changing the channel mode, so the verb list is
5823 * never used.
5824 */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01005825static struct hda_channel_mode alc260_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 { 2, NULL },
5827};
5828
Kailang Yangdf694da2005-12-05 19:42:22 +01005829
5830/* Mixer combinations
5831 *
5832 * basic: base_output + input + pc_beep + capture
5833 * HP: base_output + input + capture_alt
5834 * HP_3013: hp_3013 + input + capture
5835 * fujitsu: fujitsu + capture
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01005836 * acer: acer + capture
Kailang Yangdf694da2005-12-05 19:42:22 +01005837 */
5838
5839static struct snd_kcontrol_new alc260_base_output_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02005840 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01005841 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01005842 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5843 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5844 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5845 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5846 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02005847};
Kailang Yangdf694da2005-12-05 19:42:22 +01005848
5849static struct snd_kcontrol_new alc260_input_mixer[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
5851 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
5852 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
5853 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
5854 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
5855 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
5856 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x07, 0x01, HDA_INPUT),
5857 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x07, 0x01, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 { } /* end */
5859};
5860
Takashi Iwaibec15c32008-01-28 18:16:30 +01005861/* update HP, line and mono out pins according to the master switch */
5862static void alc260_hp_master_update(struct hda_codec *codec,
5863 hda_nid_t hp, hda_nid_t line,
5864 hda_nid_t mono)
5865{
5866 struct alc_spec *spec = codec->spec;
5867 unsigned int val = spec->master_sw ? PIN_HP : 0;
5868 /* change HP and line-out pins */
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005869 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005870 val);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005871 snd_hda_codec_write(codec, line, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005872 val);
5873 /* mono (speaker) depending on the HP jack sense */
5874 val = (val && !spec->jack_present) ? PIN_OUT : 0;
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005875 snd_hda_codec_write(codec, mono, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005876 val);
5877}
5878
5879static int alc260_hp_master_sw_get(struct snd_kcontrol *kcontrol,
5880 struct snd_ctl_elem_value *ucontrol)
5881{
5882 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5883 struct alc_spec *spec = codec->spec;
5884 *ucontrol->value.integer.value = spec->master_sw;
5885 return 0;
5886}
5887
5888static int alc260_hp_master_sw_put(struct snd_kcontrol *kcontrol,
5889 struct snd_ctl_elem_value *ucontrol)
5890{
5891 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
5892 struct alc_spec *spec = codec->spec;
5893 int val = !!*ucontrol->value.integer.value;
5894 hda_nid_t hp, line, mono;
5895
5896 if (val == spec->master_sw)
5897 return 0;
5898 spec->master_sw = val;
5899 hp = (kcontrol->private_value >> 16) & 0xff;
5900 line = (kcontrol->private_value >> 8) & 0xff;
5901 mono = kcontrol->private_value & 0xff;
5902 alc260_hp_master_update(codec, hp, line, mono);
5903 return 1;
5904}
5905
5906static struct snd_kcontrol_new alc260_hp_output_mixer[] = {
5907 {
5908 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5909 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005910 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005911 .info = snd_ctl_boolean_mono_info,
5912 .get = alc260_hp_master_sw_get,
5913 .put = alc260_hp_master_sw_put,
5914 .private_value = (0x0f << 16) | (0x10 << 8) | 0x11
5915 },
5916 HDA_CODEC_VOLUME("Front Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5917 HDA_BIND_MUTE("Front Playback Switch", 0x08, 2, HDA_INPUT),
5918 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5919 HDA_BIND_MUTE("Headphone Playback Switch", 0x09, 2, HDA_INPUT),
5920 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
5921 HDA_OUTPUT),
5922 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2, HDA_INPUT),
5923 { } /* end */
5924};
5925
5926static struct hda_verb alc260_hp_unsol_verbs[] = {
5927 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5928 {},
5929};
5930
5931static void alc260_hp_automute(struct hda_codec *codec)
5932{
5933 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01005934
Wu Fengguang864f92b2009-11-18 12:38:02 +08005935 spec->jack_present = snd_hda_jack_detect(codec, 0x10);
Takashi Iwaibec15c32008-01-28 18:16:30 +01005936 alc260_hp_master_update(codec, 0x0f, 0x10, 0x11);
5937}
5938
5939static void alc260_hp_unsol_event(struct hda_codec *codec, unsigned int res)
5940{
5941 if ((res >> 26) == ALC880_HP_EVENT)
5942 alc260_hp_automute(codec);
5943}
5944
Kailang Yangdf694da2005-12-05 19:42:22 +01005945static struct snd_kcontrol_new alc260_hp_3013_mixer[] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01005946 {
5947 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
5948 .name = "Master Playback Switch",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01005949 .subdevice = HDA_SUBDEV_NID_FLAG | 0x11,
Takashi Iwaibec15c32008-01-28 18:16:30 +01005950 .info = snd_ctl_boolean_mono_info,
5951 .get = alc260_hp_master_sw_get,
5952 .put = alc260_hp_master_sw_put,
Takashi Iwai30cde0a2008-11-07 14:49:28 +01005953 .private_value = (0x15 << 16) | (0x10 << 8) | 0x11
Takashi Iwaibec15c32008-01-28 18:16:30 +01005954 },
Kailang Yangdf694da2005-12-05 19:42:22 +01005955 HDA_CODEC_VOLUME("Front Playback Volume", 0x09, 0x0, HDA_OUTPUT),
5956 HDA_CODEC_MUTE("Front Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5957 HDA_CODEC_VOLUME("Aux-In Playback Volume", 0x07, 0x06, HDA_INPUT),
5958 HDA_CODEC_MUTE("Aux-In Playback Switch", 0x07, 0x06, HDA_INPUT),
5959 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
5960 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01005961 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
5962 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x11, 1, 0x0, HDA_OUTPUT),
Takashi Iwai16ded522005-06-10 19:58:24 +02005963 { } /* end */
5964};
5965
Kailang Yang3f878302008-08-26 13:02:23 +02005966static struct hda_bind_ctls alc260_dc7600_bind_master_vol = {
5967 .ops = &snd_hda_bind_vol,
5968 .values = {
5969 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_OUTPUT),
5970 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT),
5971 HDA_COMPOSE_AMP_VAL(0x0a, 3, 0, HDA_OUTPUT),
5972 0
5973 },
5974};
5975
5976static struct hda_bind_ctls alc260_dc7600_bind_switch = {
5977 .ops = &snd_hda_bind_sw,
5978 .values = {
5979 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
5980 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
5981 0
5982 },
5983};
5984
5985static struct snd_kcontrol_new alc260_hp_dc7600_mixer[] = {
5986 HDA_BIND_VOL("Master Playback Volume", &alc260_dc7600_bind_master_vol),
5987 HDA_BIND_SW("LineOut Playback Switch", &alc260_dc7600_bind_switch),
5988 HDA_CODEC_MUTE("Speaker Playback Switch", 0x0f, 0x0, HDA_OUTPUT),
5989 HDA_CODEC_MUTE("Headphone Playback Switch", 0x10, 0x0, HDA_OUTPUT),
5990 { } /* end */
5991};
5992
Takashi Iwaibec15c32008-01-28 18:16:30 +01005993static struct hda_verb alc260_hp_3013_unsol_verbs[] = {
5994 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
5995 {},
5996};
5997
5998static void alc260_hp_3013_automute(struct hda_codec *codec)
5999{
6000 struct alc_spec *spec = codec->spec;
Takashi Iwaibec15c32008-01-28 18:16:30 +01006001
Wu Fengguang864f92b2009-11-18 12:38:02 +08006002 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai30cde0a2008-11-07 14:49:28 +01006003 alc260_hp_master_update(codec, 0x15, 0x10, 0x11);
Takashi Iwaibec15c32008-01-28 18:16:30 +01006004}
6005
6006static void alc260_hp_3013_unsol_event(struct hda_codec *codec,
6007 unsigned int res)
6008{
6009 if ((res >> 26) == ALC880_HP_EVENT)
6010 alc260_hp_3013_automute(codec);
6011}
6012
Kailang Yang3f878302008-08-26 13:02:23 +02006013static void alc260_hp_3012_automute(struct hda_codec *codec)
6014{
Wu Fengguang864f92b2009-11-18 12:38:02 +08006015 unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT;
Kailang Yang3f878302008-08-26 13:02:23 +02006016
Kailang Yang3f878302008-08-26 13:02:23 +02006017 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6018 bits);
6019 snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6020 bits);
6021 snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
6022 bits);
6023}
6024
6025static void alc260_hp_3012_unsol_event(struct hda_codec *codec,
6026 unsigned int res)
6027{
6028 if ((res >> 26) == ALC880_HP_EVENT)
6029 alc260_hp_3012_automute(codec);
6030}
6031
6032/* Fujitsu S702x series laptops. ALC260 pin usage: Mic/Line jack = 0x12,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006033 * HP jack = 0x14, CD audio = 0x16, internal speaker = 0x10.
6034 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01006035static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006036 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01006037 HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006038 ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006039 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6040 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6041 HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
6042 HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006043 ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006044 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6045 HDA_BIND_MUTE("Speaker Playback Switch", 0x09, 2, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +01006046 { } /* end */
6047};
6048
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006049/* Mixer for Acer TravelMate(/Extensa/Aspire) notebooks. Note that current
6050 * versions of the ALC260 don't act on requests to enable mic bias from NID
6051 * 0x0f (used to drive the headphone jack in these laptops). The ALC260
6052 * datasheet doesn't mention this restriction. At this stage it's not clear
6053 * whether this behaviour is intentional or is a hardware bug in chip
6054 * revisions available in early 2006. Therefore for now allow the
6055 * "Headphone Jack Mode" control to span all choices, but if it turns out
6056 * that the lack of mic bias for this NID is intentional we could change the
6057 * mode from ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6058 *
6059 * In addition, Acer TravelMate(/Extensa/Aspire) notebooks in early 2006
6060 * don't appear to make the mic bias available from the "line" jack, even
6061 * though the NID used for this jack (0x14) can supply it. The theory is
6062 * that perhaps Acer have included blocking capacitors between the ALC260
6063 * and the output jack. If this turns out to be the case for all such
6064 * models the "Line Jack Mode" mode could be changed from ALC_PIN_DIR_INOUT
6065 * to ALC_PIN_DIR_INOUT_NOMICBIAS.
Jonathan Woithebd869482006-11-28 11:35:52 +01006066 *
6067 * The C20x Tablet series have a mono internal speaker which is controlled
6068 * via the chip's Mono sum widget and pin complex, so include the necessary
6069 * controls for such models. On models without a "mono speaker" the control
6070 * won't do anything.
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006071 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006072static struct snd_kcontrol_new alc260_acer_mixer[] = {
6073 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6074 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006075 ALC_PIN_MODE("Headphone Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006076 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0a, 1, 0x0,
Jonathan Woithebd869482006-11-28 11:35:52 +01006077 HDA_OUTPUT),
Takashi Iwai31bffaa2008-02-27 16:10:44 +01006078 HDA_BIND_MUTE_MONO("Speaker Playback Switch", 0x0a, 1, 2,
Jonathan Woithebd869482006-11-28 11:35:52 +01006079 HDA_INPUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006080 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6081 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
6082 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6083 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6084 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6085 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6086 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6087 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006088 { } /* end */
6089};
6090
Michael Schwingencc959482009-02-22 18:58:45 +01006091/* Maxdata Favorit 100XS: one output and one input (0x12) jack
6092 */
6093static struct snd_kcontrol_new alc260_favorit100_mixer[] = {
6094 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6095 HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
6096 ALC_PIN_MODE("Output Jack Mode", 0x0f, ALC_PIN_DIR_INOUT),
6097 HDA_CODEC_VOLUME("Line/Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6098 HDA_CODEC_MUTE("Line/Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6099 ALC_PIN_MODE("Line/Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6100 { } /* end */
6101};
6102
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006103/* Packard bell V7900 ALC260 pin usage: HP = 0x0f, Mic jack = 0x12,
6104 * Line In jack = 0x14, CD audio = 0x16, pc beep = 0x17.
6105 */
6106static struct snd_kcontrol_new alc260_will_mixer[] = {
6107 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6108 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6109 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6110 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6111 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6112 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6113 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6114 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6115 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6116 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006117 { } /* end */
6118};
6119
6120/* Replacer 672V ALC260 pin usage: Mic jack = 0x12,
6121 * Line In jack = 0x14, ATAPI Mic = 0x13, speaker = 0x0f.
6122 */
6123static struct snd_kcontrol_new alc260_replacer_672v_mixer[] = {
6124 HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6125 HDA_BIND_MUTE("Master Playback Switch", 0x08, 0x2, HDA_INPUT),
6126 HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
6127 HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
6128 ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
6129 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x07, 0x1, HDA_INPUT),
6130 HDA_CODEC_MUTE("ATATI Mic Playback Switch", 0x07, 0x1, HDA_INPUT),
6131 HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
6132 HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
6133 ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
6134 { } /* end */
6135};
6136
Kailang Yangdf694da2005-12-05 19:42:22 +01006137/*
6138 * initialization verbs
6139 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140static struct hda_verb alc260_init_verbs[] = {
6141 /* Line In pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006142 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02006144 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145 /* Mic1 (rear panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006146 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 /* Mic2 (front panel) pin widget for input and vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02006148 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149 /* LINE-2 is used for line-out in rear */
Takashi Iwai05acb862005-06-10 19:50:25 +02006150 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 /* select line-out */
Jonathan Woithefd56f2d2006-01-24 10:35:46 +01006152 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 /* LINE-OUT pin */
Takashi Iwai05acb862005-06-10 19:50:25 +02006154 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155 /* enable HP */
Takashi Iwai05acb862005-06-10 19:50:25 +02006156 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 /* enable Mono */
Takashi Iwai05acb862005-06-10 19:50:25 +02006158 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6159 /* mute capture amp left and right */
Takashi Iwai16ded522005-06-10 19:58:24 +02006160 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161 /* set connection select to line in (default select for this ADC) */
6162 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai16ded522005-06-10 19:58:24 +02006163 /* mute capture amp left and right */
6164 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6165 /* set connection select to line in (default select for this ADC) */
6166 {0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai05acb862005-06-10 19:50:25 +02006167 /* set vol=0 Line-Out mixer amp left and right */
6168 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6169 /* unmute pin widget amp left and right (no gain on this amp) */
6170 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6171 /* set vol=0 HP mixer amp left and right */
6172 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6173 /* unmute pin widget amp left and right (no gain on this amp) */
6174 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6175 /* set vol=0 Mono mixer amp left and right */
6176 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6177 /* unmute pin widget amp left and right (no gain on this amp) */
6178 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6179 /* unmute LINE-2 out pin */
6180 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006181 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6182 * Line In 2 = 0x03
6183 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006184 /* mute analog inputs */
6185 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6186 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6187 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6188 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6189 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
Takashi Iwai05acb862005-06-10 19:50:25 +02006191 /* mute Front out path */
6192 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6193 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6194 /* mute Headphone out path */
6195 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6196 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6197 /* mute Mono out path */
6198 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6199 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 { }
6201};
6202
Takashi Iwai474167d2006-05-17 17:17:43 +02006203#if 0 /* should be identical with alc260_init_verbs? */
Kailang Yangdf694da2005-12-05 19:42:22 +01006204static struct hda_verb alc260_hp_init_verbs[] = {
6205 /* Headphone and output */
6206 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6207 /* mono output */
6208 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6209 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6210 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6211 /* Mic2 (front panel) pin widget for input and vref at 80% */
6212 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6213 /* Line In pin widget for input */
6214 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6215 /* Line-2 pin widget for output */
6216 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6217 /* CD pin widget for input */
6218 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6219 /* unmute amp left and right */
6220 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6221 /* set connection select to line in (default select for this ADC) */
6222 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6223 /* unmute Line-Out mixer amp left and right (volume = 0) */
6224 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6225 /* mute pin widget amp left and right (no gain on this amp) */
6226 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6227 /* unmute HP mixer amp left and right (volume = 0) */
6228 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6229 /* mute pin widget amp left and right (no gain on this amp) */
6230 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006231 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6232 * Line In 2 = 0x03
6233 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006234 /* mute analog inputs */
6235 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6236 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6237 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6238 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6239 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006240 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6241 /* Unmute Front out path */
6242 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6243 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6244 /* Unmute Headphone out path */
6245 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6246 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6247 /* Unmute Mono out path */
6248 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6249 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6250 { }
6251};
Takashi Iwai474167d2006-05-17 17:17:43 +02006252#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01006253
6254static struct hda_verb alc260_hp_3013_init_verbs[] = {
6255 /* Line out and output */
6256 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6257 /* mono output */
6258 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
6259 /* Mic1 (rear panel) pin widget for input and vref at 80% */
6260 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6261 /* Mic2 (front panel) pin widget for input and vref at 80% */
6262 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
6263 /* Line In pin widget for input */
6264 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6265 /* Headphone pin widget for output */
6266 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
6267 /* CD pin widget for input */
6268 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
6269 /* unmute amp left and right */
6270 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000},
6271 /* set connection select to line in (default select for this ADC) */
6272 {0x04, AC_VERB_SET_CONNECT_SEL, 0x02},
6273 /* unmute Line-Out mixer amp left and right (volume = 0) */
6274 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6275 /* mute pin widget amp left and right (no gain on this amp) */
6276 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
6277 /* unmute HP mixer amp left and right (volume = 0) */
6278 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
6279 /* mute pin widget amp left and right (no gain on this amp) */
6280 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006281 /* Amp Indexes: CD = 0x04, Line In 1 = 0x02, Mic 1 = 0x00 &
6282 * Line In 2 = 0x03
6283 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006284 /* mute analog inputs */
6285 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6286 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6287 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6288 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6289 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006290 /* Amp Indexes: DAC = 0x01 & mixer = 0x00 */
6291 /* Unmute Front out path */
6292 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6293 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6294 /* Unmute Headphone out path */
6295 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6296 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6297 /* Unmute Mono out path */
6298 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
6299 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
6300 { }
6301};
6302
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006303/* Initialisation sequence for ALC260 as configured in Fujitsu S702x
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006304 * laptops. ALC260 pin usage: Mic/Line jack = 0x12, HP jack = 0x14, CD
6305 * audio = 0x16, internal speaker = 0x10.
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006306 */
6307static struct hda_verb alc260_fujitsu_init_verbs[] = {
6308 /* Disable all GPIOs */
6309 {0x01, AC_VERB_SET_GPIO_MASK, 0},
6310 /* Internal speaker is connected to headphone pin */
6311 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6312 /* Headphone/Line-out jack connects to Line1 pin; make it an output */
6313 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006314 /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
6315 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
6316 /* Ensure all other unused pins are disabled and muted. */
6317 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6318 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006319 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006320 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006321 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006322 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6323 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6324 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006325
Jonathan Woithef7ace402006-02-28 11:46:14 +01006326 /* Disable digital (SPDIF) pins */
6327 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6328 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006329
Kailang Yangea1fb292008-08-26 12:58:38 +02006330 /* Ensure Line1 pin widget takes its input from the OUT1 sum bus
Jonathan Woithef7ace402006-02-28 11:46:14 +01006331 * when acting as an output.
6332 */
6333 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6334
6335 /* Start with output sum widgets muted and their output gains at min */
Takashi Iwai8b33a5a2006-02-09 11:57:01 +01006336 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6337 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6338 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6339 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6340 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6341 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6342 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6343 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6344 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006345
Jonathan Woithef7ace402006-02-28 11:46:14 +01006346 /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
6347 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6348 /* Unmute Line1 pin widget output buffer since it starts as an output.
6349 * If the pin mode is changed by the user the pin mode control will
6350 * take care of enabling the pin's input/output buffers as needed.
6351 * Therefore there's no need to enable the input buffer at this
6352 * stage.
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006353 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006354 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +02006355 /* Unmute input buffer of pin widget used for Line-in (no equiv
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006356 * mixer ctrl)
6357 */
Jonathan Woithef7ace402006-02-28 11:46:14 +01006358 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006359
Jonathan Woithef7ace402006-02-28 11:46:14 +01006360 /* Mute capture amp left and right */
6361 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006362 /* Set ADC connection select to match default mixer setting - line
Jonathan Woithef7ace402006-02-28 11:46:14 +01006363 * in (on mic1 pin)
6364 */
6365 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006366
Jonathan Woithef7ace402006-02-28 11:46:14 +01006367 /* Do the same for the second ADC: mute capture input amp and
6368 * set ADC connection to line in (on mic1 pin)
6369 */
6370 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6371 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe4c5186e2006-02-09 11:53:48 +01006372
Jonathan Woithef7ace402006-02-28 11:46:14 +01006373 /* Mute all inputs to mixer widget (even unconnected ones) */
6374 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6375 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6376 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6377 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6378 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6379 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6380 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6381 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
Takashi Iwai4a471b72005-12-07 13:56:29 +01006382
6383 { }
Jonathan Woithea9430dd2005-09-16 19:12:48 +02006384};
6385
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006386/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
6387 * similar laptops (adapted from Fujitsu init verbs).
6388 */
6389static struct hda_verb alc260_acer_init_verbs[] = {
6390 /* On TravelMate laptops, GPIO 0 enables the internal speaker and
6391 * the headphone jack. Turn this on and rely on the standard mute
6392 * methods whenever the user wants to turn these outputs off.
6393 */
6394 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6395 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6396 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6397 /* Internal speaker/Headphone jack is connected to Line-out pin */
6398 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6399 /* Internal microphone/Mic jack is connected to Mic1 pin */
6400 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6401 /* Line In jack is connected to Line1 pin */
6402 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Jonathan Woithebd869482006-11-28 11:35:52 +01006403 /* Some Acers (eg: C20x Tablets) use Mono pin for internal speaker */
6404 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006405 /* Ensure all other unused pins are disabled and muted. */
6406 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6407 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006408 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6409 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6410 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6411 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6412 /* Disable digital (SPDIF) pins */
6413 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6414 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6415
Kailang Yangea1fb292008-08-26 12:58:38 +02006416 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006417 * bus when acting as outputs.
6418 */
6419 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6420 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6421
6422 /* Start with output sum widgets muted and their output gains at min */
6423 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6424 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6425 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6426 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6427 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6428 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6429 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6430 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6431 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6432
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006433 /* Unmute Line-out pin widget amp left and right
6434 * (no equiv mixer ctrl)
6435 */
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006436 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithebd869482006-11-28 11:35:52 +01006437 /* Unmute mono pin widget amp output (no equiv mixer ctrl) */
6438 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006439 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6440 * inputs. If the pin mode is changed by the user the pin mode control
6441 * will take care of enabling the pin's input/output buffers as needed.
6442 * Therefore there's no need to enable the input buffer at this
6443 * stage.
6444 */
6445 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6446 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6447
6448 /* Mute capture amp left and right */
6449 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6450 /* Set ADC connection select to match default mixer setting - mic
6451 * (on mic1 pin)
6452 */
6453 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6454
6455 /* Do similar with the second ADC: mute capture input amp and
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006456 * set ADC connection to mic to match ALSA's default state.
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006457 */
6458 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006459 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01006460
6461 /* Mute all inputs to mixer widget (even unconnected ones) */
6462 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6463 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6464 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6465 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6467 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6468 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6469 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6470
6471 { }
6472};
6473
Michael Schwingencc959482009-02-22 18:58:45 +01006474/* Initialisation sequence for Maxdata Favorit 100XS
6475 * (adapted from Acer init verbs).
6476 */
6477static struct hda_verb alc260_favorit100_init_verbs[] = {
6478 /* GPIO 0 enables the output jack.
6479 * Turn this on and rely on the standard mute
6480 * methods whenever the user wants to turn these outputs off.
6481 */
6482 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6483 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6484 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
6485 /* Line/Mic input jack is connected to Mic1 pin */
6486 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
6487 /* Ensure all other unused pins are disabled and muted. */
6488 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6489 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6490 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6491 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6492 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6493 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6494 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6495 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6496 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
6497 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6498 /* Disable digital (SPDIF) pins */
6499 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6500 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6501
6502 /* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum
6503 * bus when acting as outputs.
6504 */
6505 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6506 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6507
6508 /* Start with output sum widgets muted and their output gains at min */
6509 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6510 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6511 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6512 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6513 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6514 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6515 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6516 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6517 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6518
6519 /* Unmute Line-out pin widget amp left and right
6520 * (no equiv mixer ctrl)
6521 */
6522 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6523 /* Unmute Mic1 and Line1 pin widget input buffers since they start as
6524 * inputs. If the pin mode is changed by the user the pin mode control
6525 * will take care of enabling the pin's input/output buffers as needed.
6526 * Therefore there's no need to enable the input buffer at this
6527 * stage.
6528 */
6529 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6530
6531 /* Mute capture amp left and right */
6532 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6533 /* Set ADC connection select to match default mixer setting - mic
6534 * (on mic1 pin)
6535 */
6536 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6537
6538 /* Do similar with the second ADC: mute capture input amp and
6539 * set ADC connection to mic to match ALSA's default state.
6540 */
6541 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6542 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6543
6544 /* Mute all inputs to mixer widget (even unconnected ones) */
6545 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6546 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6547 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6548 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6549 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6550 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6551 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6552 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6553
6554 { }
6555};
6556
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006557static struct hda_verb alc260_will_verbs[] = {
6558 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6559 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x00},
6560 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
6561 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6562 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6563 {0x1a, AC_VERB_SET_PROC_COEF, 0x3040},
6564 {}
6565};
6566
6567static struct hda_verb alc260_replacer_672v_verbs[] = {
6568 {0x0f, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
6569 {0x1a, AC_VERB_SET_COEF_INDEX, 0x07},
6570 {0x1a, AC_VERB_SET_PROC_COEF, 0x3050},
6571
6572 {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
6573 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
6574 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6575
6576 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6577 {}
6578};
6579
6580/* toggle speaker-output according to the hp-jack state */
6581static void alc260_replacer_672v_automute(struct hda_codec *codec)
6582{
6583 unsigned int present;
6584
6585 /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */
Wu Fengguang864f92b2009-11-18 12:38:02 +08006586 present = snd_hda_jack_detect(codec, 0x0f);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006587 if (present) {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006588 snd_hda_codec_write_cache(codec, 0x01, 0,
6589 AC_VERB_SET_GPIO_DATA, 1);
6590 snd_hda_codec_write_cache(codec, 0x0f, 0,
6591 AC_VERB_SET_PIN_WIDGET_CONTROL,
6592 PIN_HP);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006593 } else {
Takashi Iwai82beb8f2007-08-10 17:09:26 +02006594 snd_hda_codec_write_cache(codec, 0x01, 0,
6595 AC_VERB_SET_GPIO_DATA, 0);
6596 snd_hda_codec_write_cache(codec, 0x0f, 0,
6597 AC_VERB_SET_PIN_WIDGET_CONTROL,
6598 PIN_OUT);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02006599 }
6600}
6601
6602static void alc260_replacer_672v_unsol_event(struct hda_codec *codec,
6603 unsigned int res)
6604{
6605 if ((res >> 26) == ALC880_HP_EVENT)
6606 alc260_replacer_672v_automute(codec);
6607}
6608
Kailang Yang3f878302008-08-26 13:02:23 +02006609static struct hda_verb alc260_hp_dc7600_verbs[] = {
6610 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
6611 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
6612 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6613 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
6614 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6615 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6616 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
6617 {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6618 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6619 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
6620 {}
6621};
6622
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006623/* Test configuration for debugging, modelled after the ALC880 test
6624 * configuration.
6625 */
6626#ifdef CONFIG_SND_DEBUG
6627static hda_nid_t alc260_test_dac_nids[1] = {
6628 0x02,
6629};
6630static hda_nid_t alc260_test_adc_nids[2] = {
6631 0x04, 0x05,
6632};
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006633/* For testing the ALC260, each input MUX needs its own definition since
Kailang Yangea1fb292008-08-26 12:58:38 +02006634 * the signal assignments are different. This assumes that the first ADC
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006635 * is NID 0x04.
Jonathan Woithe17e7aec2006-02-28 11:35:18 +01006636 */
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006637static struct hda_input_mux alc260_test_capture_sources[2] = {
6638 {
6639 .num_items = 7,
6640 .items = {
6641 { "MIC1 pin", 0x0 },
6642 { "MIC2 pin", 0x1 },
6643 { "LINE1 pin", 0x2 },
6644 { "LINE2 pin", 0x3 },
6645 { "CD pin", 0x4 },
6646 { "LINE-OUT pin", 0x5 },
6647 { "HP-OUT pin", 0x6 },
6648 },
6649 },
6650 {
6651 .num_items = 8,
6652 .items = {
6653 { "MIC1 pin", 0x0 },
6654 { "MIC2 pin", 0x1 },
6655 { "LINE1 pin", 0x2 },
6656 { "LINE2 pin", 0x3 },
6657 { "CD pin", 0x4 },
6658 { "Mixer", 0x5 },
6659 { "LINE-OUT pin", 0x6 },
6660 { "HP-OUT pin", 0x7 },
6661 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006662 },
6663};
6664static struct snd_kcontrol_new alc260_test_mixer[] = {
6665 /* Output driver widgets */
6666 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
6667 HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
6668 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
6669 HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
6670 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
6671 HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
6672
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02006673 /* Modes for retasking pin widgets
6674 * Note: the ALC260 doesn't seem to act on requests to enable mic
6675 * bias from NIDs 0x0f and 0x10. The ALC260 datasheet doesn't
6676 * mention this restriction. At this stage it's not clear whether
6677 * this behaviour is intentional or is a hardware bug in chip
6678 * revisions available at least up until early 2006. Therefore for
6679 * now allow the "HP-OUT" and "LINE-OUT" Mode controls to span all
6680 * choices, but if it turns out that the lack of mic bias for these
6681 * NIDs is intentional we could change their modes from
6682 * ALC_PIN_DIR_INOUT to ALC_PIN_DIR_INOUT_NOMICBIAS.
6683 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006684 ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
6685 ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
6686 ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
6687 ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
6688 ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
6689 ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
6690
6691 /* Loopback mixer controls */
6692 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
6693 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
6694 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
6695 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
6696 HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
6697 HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
6698 HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
6699 HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
6700 HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
6701 HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006702 HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
6703 HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
6704 HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
6705 HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006706
6707 /* Controls for GPIO pins, assuming they are configured as outputs */
6708 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
6709 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
6710 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
6711 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
6712
Jonathan Woithe92621f12006-02-28 11:47:47 +01006713 /* Switches to allow the digital IO pins to be enabled. The datasheet
6714 * is ambigious as to which NID is which; testing on laptops which
Kailang Yangea1fb292008-08-26 12:58:38 +02006715 * make this output available should provide clarification.
Jonathan Woithe92621f12006-02-28 11:47:47 +01006716 */
6717 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
6718 ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
6719
Jonathan Woithef8225f62008-01-08 12:16:54 +01006720 /* A switch allowing EAPD to be enabled. Some laptops seem to use
6721 * this output to turn on an external amplifier.
6722 */
6723 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
6724 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
6725
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006726 { } /* end */
6727};
6728static struct hda_verb alc260_test_init_verbs[] = {
Jonathan Woithe5c8f8582006-02-28 11:43:27 +01006729 /* Enable all GPIOs as outputs with an initial value of 0 */
6730 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
6731 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
6732 {0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
6733
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006734 /* Enable retasking pins as output, initially without power amp */
6735 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6736 {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6737 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6738 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6739 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6740 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
6741
Jonathan Woithe92621f12006-02-28 11:47:47 +01006742 /* Disable digital (SPDIF) pins initially, but users can enable
6743 * them via a mixer switch. In the case of SPDIF-out, this initverb
6744 * payload also sets the generation to 0, output to be in "consumer"
6745 * PCM format, copyright asserted, no pre-emphasis and no validity
6746 * control.
6747 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006748 {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
6749 {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
6750
Kailang Yangea1fb292008-08-26 12:58:38 +02006751 /* Ensure mic1, mic2, line1 and line2 pin widgets take input from the
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006752 * OUT1 sum bus when acting as an output.
6753 */
6754 {0x0b, AC_VERB_SET_CONNECT_SEL, 0},
6755 {0x0c, AC_VERB_SET_CONNECT_SEL, 0},
6756 {0x0d, AC_VERB_SET_CONNECT_SEL, 0},
6757 {0x0e, AC_VERB_SET_CONNECT_SEL, 0},
6758
6759 /* Start with output sum widgets muted and their output gains at min */
6760 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6761 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6762 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6763 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6764 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6765 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6766 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6767 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6768 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6769
Jonathan Woithecdcd9262006-02-28 11:36:42 +01006770 /* Unmute retasking pin widget output buffers since the default
6771 * state appears to be output. As the pin mode is changed by the
6772 * user the pin mode control will take care of enabling the pin's
6773 * input/output buffers as needed.
6774 */
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006775 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6776 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6777 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6778 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6779 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6780 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6781 /* Also unmute the mono-out pin widget */
6782 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
6783
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006784 /* Mute capture amp left and right */
6785 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Jonathan Woithef7ace402006-02-28 11:46:14 +01006786 /* Set ADC connection select to match default mixer setting (mic1
6787 * pin)
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006788 */
6789 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6790
6791 /* Do the same for the second ADC: mute capture input amp and
Jonathan Woithef7ace402006-02-28 11:46:14 +01006792 * set ADC connection to mic1 pin
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01006793 */
6794 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6795 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6796
6797 /* Mute all inputs to mixer widget (even unconnected ones) */
6798 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
6799 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
6800 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
6801 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
6802 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
6803 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
6804 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
6805 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
6806
6807 { }
6808};
6809#endif
6810
Takashi Iwai63300792008-01-24 15:31:36 +01006811#define alc260_pcm_analog_playback alc880_pcm_analog_alt_playback
6812#define alc260_pcm_analog_capture alc880_pcm_analog_capture
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813
Takashi Iwaia3bcba32005-12-06 19:05:29 +01006814#define alc260_pcm_digital_playback alc880_pcm_digital_playback
6815#define alc260_pcm_digital_capture alc880_pcm_digital_capture
6816
Kailang Yangdf694da2005-12-05 19:42:22 +01006817/*
6818 * for BIOS auto-configuration
6819 */
6820
6821static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai863b4512008-10-21 17:01:47 +02006822 const char *pfx, int *vol_bits)
Kailang Yangdf694da2005-12-05 19:42:22 +01006823{
6824 hda_nid_t nid_vol;
6825 unsigned long vol_val, sw_val;
Kailang Yangdf694da2005-12-05 19:42:22 +01006826 int err;
6827
6828 if (nid >= 0x0f && nid < 0x11) {
6829 nid_vol = nid - 0x7;
6830 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6831 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6832 } else if (nid == 0x11) {
6833 nid_vol = nid - 0x7;
6834 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT);
6835 sw_val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
6836 } else if (nid >= 0x12 && nid <= 0x15) {
6837 nid_vol = 0x08;
6838 vol_val = HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT);
6839 sw_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
6840 } else
6841 return 0; /* N/A */
Kailang Yangea1fb292008-08-26 12:58:38 +02006842
Takashi Iwai863b4512008-10-21 17:01:47 +02006843 if (!(*vol_bits & (1 << nid_vol))) {
6844 /* first control for the volume widget */
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006845 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val);
Takashi Iwai863b4512008-10-21 17:01:47 +02006846 if (err < 0)
6847 return err;
6848 *vol_bits |= (1 << nid_vol);
6849 }
Takashi Iwai0afe5f82009-10-02 09:20:00 +02006850 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006851 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01006852 return err;
6853 return 1;
6854}
6855
6856/* add playback controls from the parsed DAC table */
6857static int alc260_auto_create_multi_out_ctls(struct alc_spec *spec,
6858 const struct auto_pin_cfg *cfg)
6859{
6860 hda_nid_t nid;
6861 int err;
Takashi Iwai863b4512008-10-21 17:01:47 +02006862 int vols = 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006863
6864 spec->multiout.num_dacs = 1;
6865 spec->multiout.dac_nids = spec->private_dac_nids;
6866 spec->multiout.dac_nids[0] = 0x02;
6867
6868 nid = cfg->line_out_pins[0];
6869 if (nid) {
Takashi Iwai23112d62009-08-25 16:07:08 +02006870 const char *pfx;
6871 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
6872 pfx = "Master";
6873 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
6874 pfx = "Speaker";
6875 else
6876 pfx = "Front";
6877 err = alc260_add_playback_controls(spec, nid, pfx, &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006878 if (err < 0)
6879 return err;
6880 }
6881
Takashi Iwai82bc9552006-03-21 11:24:42 +01006882 nid = cfg->speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006883 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006884 err = alc260_add_playback_controls(spec, nid, "Speaker", &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006885 if (err < 0)
6886 return err;
6887 }
6888
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006889 nid = cfg->hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006890 if (nid) {
Takashi Iwai863b4512008-10-21 17:01:47 +02006891 err = alc260_add_playback_controls(spec, nid, "Headphone",
6892 &vols);
Kailang Yangdf694da2005-12-05 19:42:22 +01006893 if (err < 0)
6894 return err;
6895 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006896 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +01006897}
6898
6899/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +02006900static int alc260_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yangdf694da2005-12-05 19:42:22 +01006901 const struct auto_pin_cfg *cfg)
6902{
Takashi Iwai05f5f472009-08-25 13:10:18 +02006903 return alc_auto_create_input_ctls(codec, cfg, 0x07, 0x04, 0x05);
Kailang Yangdf694da2005-12-05 19:42:22 +01006904}
6905
6906static void alc260_auto_set_output_and_unmute(struct hda_codec *codec,
6907 hda_nid_t nid, int pin_type,
6908 int sel_idx)
6909{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01006910 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangdf694da2005-12-05 19:42:22 +01006911 /* need the manual connection? */
6912 if (nid >= 0x12) {
6913 int idx = nid - 0x12;
6914 snd_hda_codec_write(codec, idx + 0x0b, 0,
6915 AC_VERB_SET_CONNECT_SEL, sel_idx);
Kailang Yangdf694da2005-12-05 19:42:22 +01006916 }
6917}
6918
6919static void alc260_auto_init_multi_out(struct hda_codec *codec)
6920{
6921 struct alc_spec *spec = codec->spec;
6922 hda_nid_t nid;
6923
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006924 nid = spec->autocfg.line_out_pins[0];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006925 if (nid) {
6926 int pin_type = get_pin_type(spec->autocfg.line_out_type);
6927 alc260_auto_set_output_and_unmute(codec, nid, pin_type, 0);
6928 }
Kailang Yangea1fb292008-08-26 12:58:38 +02006929
Takashi Iwai82bc9552006-03-21 11:24:42 +01006930 nid = spec->autocfg.speaker_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006931 if (nid)
6932 alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
6933
Takashi Iwaieb06ed82006-09-20 17:10:27 +02006934 nid = spec->autocfg.hp_pins[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01006935 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +02006936 alc260_auto_set_output_and_unmute(codec, nid, PIN_HP, 0);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006937}
Kailang Yangdf694da2005-12-05 19:42:22 +01006938
6939#define ALC260_PIN_CD_NID 0x16
6940static void alc260_auto_init_analog_input(struct hda_codec *codec)
6941{
6942 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +02006943 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +01006944 int i;
6945
Takashi Iwai66ceeb62010-08-30 13:05:52 +02006946 for (i = 0; i < cfg->num_inputs; i++) {
6947 hda_nid_t nid = cfg->inputs[i].pin;
Kailang Yangdf694da2005-12-05 19:42:22 +01006948 if (nid >= 0x12) {
Takashi Iwai30ea0982010-09-16 18:47:56 +02006949 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +01006950 if (nid != ALC260_PIN_CD_NID &&
6951 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006952 snd_hda_codec_write(codec, nid, 0,
6953 AC_VERB_SET_AMP_GAIN_MUTE,
Kailang Yangdf694da2005-12-05 19:42:22 +01006954 AMP_OUT_MUTE);
6955 }
6956 }
6957}
6958
Takashi Iwai7f311a42010-04-09 17:32:23 +02006959#define alc260_auto_init_input_src alc880_auto_init_input_src
6960
Kailang Yangdf694da2005-12-05 19:42:22 +01006961/*
6962 * generic initialization of ADC, input mixers and output mixers
6963 */
6964static struct hda_verb alc260_volume_init_verbs[] = {
6965 /*
6966 * Unmute ADC0-1 and set the default input to mic-in
6967 */
6968 {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
6969 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6970 {0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
6971 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +02006972
Kailang Yangdf694da2005-12-05 19:42:22 +01006973 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
6974 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02006975 * Note: PASD motherboards uses the Line In 2 as the input for
6976 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +01006977 */
6978 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +02006979 /* mute analog inputs */
6980 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
6981 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
6982 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
6983 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
6984 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +01006985
6986 /*
6987 * Set up output mixers (0x08 - 0x0a)
6988 */
6989 /* set vol=0 to output mixers */
6990 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6991 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6992 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
6993 /* set up input amps for analog loopback */
6994 /* Amp Indices: DAC = 0, mixer = 1 */
6995 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6996 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6997 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
6998 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
6999 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7000 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +02007001
Kailang Yangdf694da2005-12-05 19:42:22 +01007002 { }
7003};
7004
7005static int alc260_parse_auto_config(struct hda_codec *codec)
7006{
7007 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007008 int err;
7009 static hda_nid_t alc260_ignore[] = { 0x17, 0 };
7010
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007011 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
7012 alc260_ignore);
7013 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007014 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007015 err = alc260_auto_create_multi_out_ctls(spec, &spec->autocfg);
7016 if (err < 0)
Takashi Iwai4a471b72005-12-07 13:56:29 +01007017 return err;
Takashi Iwai603c4012008-07-30 15:01:44 +02007018 if (!spec->kctls.list)
Kailang Yangdf694da2005-12-05 19:42:22 +01007019 return 0; /* can't find valid BIOS pin config */
Takashi Iwai05f5f472009-08-25 13:10:18 +02007020 err = alc260_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007021 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +01007022 return err;
7023
7024 spec->multiout.max_channels = 2;
7025
Takashi Iwai0852d7a2009-02-11 11:35:15 +01007026 if (spec->autocfg.dig_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +01007027 spec->multiout.dig_out_nid = ALC260_DIGOUT_NID;
Takashi Iwai603c4012008-07-30 15:01:44 +02007028 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +01007029 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +01007030
Takashi Iwaid88897e2008-10-31 15:01:37 +01007031 add_verb(spec, alc260_volume_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +01007032
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007033 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -02007034 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +01007035
Kailang Yang6227cdc2010-02-25 08:36:52 +01007036 alc_ssid_check(codec, 0x10, 0x15, 0x0f, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +02007037
Kailang Yangdf694da2005-12-05 19:42:22 +01007038 return 1;
7039}
7040
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007041/* additional initialization for auto-configuration model */
7042static void alc260_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +01007043{
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007044 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007045 alc260_auto_init_multi_out(codec);
7046 alc260_auto_init_analog_input(codec);
Takashi Iwai7f311a42010-04-09 17:32:23 +02007047 alc260_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +02007048 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +01007049 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +02007050 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +01007051}
7052
Takashi Iwaicb53c622007-08-10 17:21:45 +02007053#ifdef CONFIG_SND_HDA_POWER_SAVE
7054static struct hda_amp_list alc260_loopbacks[] = {
7055 { 0x07, HDA_INPUT, 0 },
7056 { 0x07, HDA_INPUT, 1 },
7057 { 0x07, HDA_INPUT, 2 },
7058 { 0x07, HDA_INPUT, 3 },
7059 { 0x07, HDA_INPUT, 4 },
7060 { } /* end */
7061};
7062#endif
7063
Kailang Yangdf694da2005-12-05 19:42:22 +01007064/*
Takashi Iwaifc091762010-08-04 23:53:36 +02007065 * Pin config fixes
7066 */
7067enum {
7068 PINFIX_HP_DC5750,
7069};
7070
Takashi Iwaifc091762010-08-04 23:53:36 +02007071static const struct alc_fixup alc260_fixups[] = {
7072 [PINFIX_HP_DC5750] = {
Takashi Iwai73413b12010-08-30 09:39:57 +02007073 .pins = (const struct alc_pincfg[]) {
7074 { 0x11, 0x90130110 }, /* speaker */
7075 { }
7076 }
Takashi Iwaifc091762010-08-04 23:53:36 +02007077 },
7078};
7079
7080static struct snd_pci_quirk alc260_fixup_tbl[] = {
7081 SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
7082 {}
7083};
7084
7085/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007086 * ALC260 configurations
7087 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007088static const char *alc260_models[ALC260_MODEL_LAST] = {
7089 [ALC260_BASIC] = "basic",
7090 [ALC260_HP] = "hp",
7091 [ALC260_HP_3013] = "hp-3013",
Takashi Iwai2922c9a2008-08-27 18:12:42 +02007092 [ALC260_HP_DC7600] = "hp-dc7600",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007093 [ALC260_FUJITSU_S702X] = "fujitsu",
7094 [ALC260_ACER] = "acer",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007095 [ALC260_WILL] = "will",
7096 [ALC260_REPLACER_672V] = "replacer",
Michael Schwingencc959482009-02-22 18:58:45 +01007097 [ALC260_FAVORIT100] = "favorit100",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007098#ifdef CONFIG_SND_DEBUG
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007099 [ALC260_TEST] = "test",
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007100#endif
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007101 [ALC260_AUTO] = "auto",
7102};
7103
7104static struct snd_pci_quirk alc260_cfg_tbl[] = {
Jonathan Woithebd869482006-11-28 11:35:52 +01007105 SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER),
Daniel T Chen950200e2009-12-13 14:11:02 -05007106 SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007107 SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER),
Michael Schwingencc959482009-02-22 18:58:45 +01007108 SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100),
Takashi Iwai9720b712007-03-13 21:46:23 +01007109 SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013),
Takashi Iwai4ac55982009-11-10 16:08:45 +01007110 SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007111 SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013),
Jaroslav Kysela34ec8a02008-07-10 14:49:19 +02007112 SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013),
Kailang Yang3f878302008-08-26 13:02:23 +02007113 SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007114 SND_PCI_QUIRK(0x103c, 0x3013, "HP", ALC260_HP_3013),
7115 SND_PCI_QUIRK(0x103c, 0x3014, "HP", ALC260_HP),
7116 SND_PCI_QUIRK(0x103c, 0x3015, "HP", ALC260_HP),
7117 SND_PCI_QUIRK(0x103c, 0x3016, "HP", ALC260_HP),
7118 SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_BASIC),
7119 SND_PCI_QUIRK(0x104d, 0x81cc, "Sony VAIO", ALC260_BASIC),
7120 SND_PCI_QUIRK(0x104d, 0x81cd, "Sony VAIO", ALC260_BASIC),
7121 SND_PCI_QUIRK(0x10cf, 0x1326, "Fujitsu S702X", ALC260_FUJITSU_S702X),
7122 SND_PCI_QUIRK(0x152d, 0x0729, "CTL U553W", ALC260_BASIC),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007123 SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_REPLACER_672V),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01007124 SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_WILL),
Takashi Iwai16ded522005-06-10 19:58:24 +02007125 {}
7126};
7127
Kailang Yangdf694da2005-12-05 19:42:22 +01007128static struct alc_config_preset alc260_presets[] = {
7129 [ALC260_BASIC] = {
7130 .mixers = { alc260_base_output_mixer,
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007131 alc260_input_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007132 .init_verbs = { alc260_init_verbs },
7133 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7134 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007135 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
Takashi Iwai9c4cc0b2010-03-15 09:07:52 +01007136 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007137 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7138 .channel_mode = alc260_modes,
7139 .input_mux = &alc260_capture_source,
7140 },
7141 [ALC260_HP] = {
Takashi Iwaibec15c32008-01-28 18:16:30 +01007142 .mixers = { alc260_hp_output_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007143 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007144 .init_verbs = { alc260_init_verbs,
7145 alc260_hp_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007146 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7147 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007148 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7149 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007150 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7151 .channel_mode = alc260_modes,
7152 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007153 .unsol_event = alc260_hp_unsol_event,
7154 .init_hook = alc260_hp_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007155 },
Kailang Yang3f878302008-08-26 13:02:23 +02007156 [ALC260_HP_DC7600] = {
7157 .mixers = { alc260_hp_dc7600_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007158 alc260_input_mixer },
Kailang Yang3f878302008-08-26 13:02:23 +02007159 .init_verbs = { alc260_init_verbs,
7160 alc260_hp_dc7600_verbs },
7161 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7162 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007163 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7164 .adc_nids = alc260_adc_nids_alt,
Kailang Yang3f878302008-08-26 13:02:23 +02007165 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7166 .channel_mode = alc260_modes,
7167 .input_mux = &alc260_capture_source,
7168 .unsol_event = alc260_hp_3012_unsol_event,
7169 .init_hook = alc260_hp_3012_automute,
7170 },
Kailang Yangdf694da2005-12-05 19:42:22 +01007171 [ALC260_HP_3013] = {
7172 .mixers = { alc260_hp_3013_mixer,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007173 alc260_input_mixer },
Takashi Iwaibec15c32008-01-28 18:16:30 +01007174 .init_verbs = { alc260_hp_3013_init_verbs,
7175 alc260_hp_3013_unsol_verbs },
Kailang Yangdf694da2005-12-05 19:42:22 +01007176 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7177 .dac_nids = alc260_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007178 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt),
7179 .adc_nids = alc260_adc_nids_alt,
Kailang Yangdf694da2005-12-05 19:42:22 +01007180 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7181 .channel_mode = alc260_modes,
7182 .input_mux = &alc260_capture_source,
Takashi Iwaibec15c32008-01-28 18:16:30 +01007183 .unsol_event = alc260_hp_3013_unsol_event,
7184 .init_hook = alc260_hp_3013_automute,
Kailang Yangdf694da2005-12-05 19:42:22 +01007185 },
7186 [ALC260_FUJITSU_S702X] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007187 .mixers = { alc260_fujitsu_mixer },
Kailang Yangdf694da2005-12-05 19:42:22 +01007188 .init_verbs = { alc260_fujitsu_init_verbs },
7189 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7190 .dac_nids = alc260_dac_nids,
Jonathan Woithed57fdac2006-02-28 11:38:35 +01007191 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7192 .adc_nids = alc260_dual_adc_nids,
Kailang Yangdf694da2005-12-05 19:42:22 +01007193 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7194 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007195 .num_mux_defs = ARRAY_SIZE(alc260_fujitsu_capture_sources),
7196 .input_mux = alc260_fujitsu_capture_sources,
Kailang Yangdf694da2005-12-05 19:42:22 +01007197 },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007198 [ALC260_ACER] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007199 .mixers = { alc260_acer_mixer },
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007200 .init_verbs = { alc260_acer_init_verbs },
7201 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7202 .dac_nids = alc260_dac_nids,
7203 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7204 .adc_nids = alc260_dual_adc_nids,
7205 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7206 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007207 .num_mux_defs = ARRAY_SIZE(alc260_acer_capture_sources),
7208 .input_mux = alc260_acer_capture_sources,
Jonathan Woithe0bfc90e2006-02-28 11:45:11 +01007209 },
Michael Schwingencc959482009-02-22 18:58:45 +01007210 [ALC260_FAVORIT100] = {
7211 .mixers = { alc260_favorit100_mixer },
7212 .init_verbs = { alc260_favorit100_init_verbs },
7213 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7214 .dac_nids = alc260_dac_nids,
7215 .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
7216 .adc_nids = alc260_dual_adc_nids,
7217 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7218 .channel_mode = alc260_modes,
7219 .num_mux_defs = ARRAY_SIZE(alc260_favorit100_capture_sources),
7220 .input_mux = alc260_favorit100_capture_sources,
7221 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007222 [ALC260_WILL] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007223 .mixers = { alc260_will_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007224 .init_verbs = { alc260_init_verbs, alc260_will_verbs },
7225 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7226 .dac_nids = alc260_dac_nids,
7227 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7228 .adc_nids = alc260_adc_nids,
7229 .dig_out_nid = ALC260_DIGOUT_NID,
7230 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7231 .channel_mode = alc260_modes,
7232 .input_mux = &alc260_capture_source,
7233 },
7234 [ALC260_REPLACER_672V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007235 .mixers = { alc260_replacer_672v_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +02007236 .init_verbs = { alc260_init_verbs, alc260_replacer_672v_verbs },
7237 .num_dacs = ARRAY_SIZE(alc260_dac_nids),
7238 .dac_nids = alc260_dac_nids,
7239 .num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
7240 .adc_nids = alc260_adc_nids,
7241 .dig_out_nid = ALC260_DIGOUT_NID,
7242 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7243 .channel_mode = alc260_modes,
7244 .input_mux = &alc260_capture_source,
7245 .unsol_event = alc260_replacer_672v_unsol_event,
7246 .init_hook = alc260_replacer_672v_automute,
7247 },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007248#ifdef CONFIG_SND_DEBUG
7249 [ALC260_TEST] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007250 .mixers = { alc260_test_mixer },
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007251 .init_verbs = { alc260_test_init_verbs },
7252 .num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
7253 .dac_nids = alc260_test_dac_nids,
7254 .num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
7255 .adc_nids = alc260_test_adc_nids,
7256 .num_channel_mode = ARRAY_SIZE(alc260_modes),
7257 .channel_mode = alc260_modes,
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +02007258 .num_mux_defs = ARRAY_SIZE(alc260_test_capture_sources),
7259 .input_mux = alc260_test_capture_sources,
Jonathan Woithe7cf51e42006-02-09 12:01:26 +01007260 },
7261#endif
Kailang Yangdf694da2005-12-05 19:42:22 +01007262};
7263
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264static int patch_alc260(struct hda_codec *codec)
7265{
7266 struct alc_spec *spec;
Kailang Yangdf694da2005-12-05 19:42:22 +01007267 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007268
Takashi Iwaie560d8d2005-09-09 14:21:46 +02007269 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007270 if (spec == NULL)
7271 return -ENOMEM;
7272
7273 codec->spec = spec;
7274
Takashi Iwaif5fcc132006-11-24 17:07:44 +01007275 board_config = snd_hda_check_board_config(codec, ALC260_MODEL_LAST,
7276 alc260_models,
7277 alc260_cfg_tbl);
7278 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02007279 snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai6c627f32009-05-18 12:33:36 +02007280 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +01007281 board_config = ALC260_AUTO;
Takashi Iwai16ded522005-06-10 19:58:24 +02007282 }
7283
Takashi Iwaifc091762010-08-04 23:53:36 +02007284 if (board_config == ALC260_AUTO)
7285 alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1);
7286
Kailang Yangdf694da2005-12-05 19:42:22 +01007287 if (board_config == ALC260_AUTO) {
7288 /* automatic parse from the BIOS config */
7289 err = alc260_parse_auto_config(codec);
7290 if (err < 0) {
7291 alc_free(codec);
7292 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02007293 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +02007294 printk(KERN_INFO
7295 "hda_codec: Cannot set up configuration "
7296 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +01007297 board_config = ALC260_BASIC;
7298 }
Takashi Iwai16ded522005-06-10 19:58:24 +02007299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007300
Kusanagi Kouichi680cd532009-02-05 00:00:58 +09007301 err = snd_hda_attach_beep_device(codec, 0x1);
7302 if (err < 0) {
7303 alc_free(codec);
7304 return err;
7305 }
7306
Kailang Yangdf694da2005-12-05 19:42:22 +01007307 if (board_config != ALC260_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +02007308 setup_preset(codec, &alc260_presets[board_config]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007309
Linus Torvalds1da177e2005-04-16 15:20:36 -07007310 spec->stream_analog_playback = &alc260_pcm_analog_playback;
7311 spec->stream_analog_capture = &alc260_pcm_analog_capture;
Jonathan Woithe53bacfb2010-08-08 00:17:05 +09307312 spec->stream_analog_alt_capture = &alc260_pcm_analog_capture;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007313
Takashi Iwaia3bcba32005-12-06 19:05:29 +01007314 spec->stream_digital_playback = &alc260_pcm_digital_playback;
7315 spec->stream_digital_capture = &alc260_pcm_digital_capture;
7316
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007317 if (!spec->adc_nids && spec->input_mux) {
7318 /* check whether NID 0x04 is valid */
7319 unsigned int wcap = get_wcaps(codec, 0x04);
Takashi Iwaia22d5432009-07-27 12:54:26 +02007320 wcap = get_wcaps_type(wcap);
Takashi Iwai4ef0ef12008-11-03 17:47:49 +01007321 /* get type */
7322 if (wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
7323 spec->adc_nids = alc260_adc_nids_alt;
7324 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids_alt);
7325 } else {
7326 spec->adc_nids = alc260_adc_nids;
7327 spec->num_adc_nids = ARRAY_SIZE(alc260_adc_nids);
7328 }
7329 }
Takashi Iwaib59bdf32009-08-11 09:47:30 +02007330 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01007331 set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
Takashi Iwaif9e336f2008-10-31 16:37:07 +01007332
Takashi Iwaifc091762010-08-04 23:53:36 +02007333 if (board_config == ALC260_AUTO)
7334 alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0);
7335
Takashi Iwai2134ea42008-01-10 16:53:55 +01007336 spec->vmaster_nid = 0x08;
7337
Linus Torvalds1da177e2005-04-16 15:20:36 -07007338 codec->patch_ops = alc_patch_ops;
Kailang Yangdf694da2005-12-05 19:42:22 +01007339 if (board_config == ALC260_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +01007340 spec->init_hook = alc260_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +02007341#ifdef CONFIG_SND_HDA_POWER_SAVE
7342 if (!spec->loopback.amplist)
7343 spec->loopback.amplist = alc260_loopbacks;
7344#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345
7346 return 0;
7347}
7348
Takashi Iwaie9edcee2005-06-13 14:16:38 +02007349
Linus Torvalds1da177e2005-04-16 15:20:36 -07007350/*
Takashi Iwai49535502009-06-30 15:28:30 +02007351 * ALC882/883/885/888/889 support
Linus Torvalds1da177e2005-04-16 15:20:36 -07007352 *
7353 * ALC882 is almost identical with ALC880 but has cleaner and more flexible
7354 * configuration. Each pin widget can choose any input DACs and a mixer.
7355 * Each ADC is connected from a mixer of all inputs. This makes possible
7356 * 6-channel independent captures.
7357 *
7358 * In addition, an independent DAC for the multi-playback (not used in this
7359 * driver yet).
7360 */
Kailang Yangdf694da2005-12-05 19:42:22 +01007361#define ALC882_DIGOUT_NID 0x06
7362#define ALC882_DIGIN_NID 0x0a
Takashi Iwai49535502009-06-30 15:28:30 +02007363#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID
7364#define ALC883_DIGIN_NID ALC882_DIGIN_NID
7365#define ALC1200_DIGOUT_NID 0x10
7366
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +01007368static struct hda_channel_mode alc882_ch_modes[1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369 { 8, NULL }
7370};
7371
Takashi Iwai49535502009-06-30 15:28:30 +02007372/* DACs */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373static hda_nid_t alc882_dac_nids[4] = {
7374 /* front, rear, clfe, rear_surr */
7375 0x02, 0x03, 0x04, 0x05
7376};
Takashi Iwai49535502009-06-30 15:28:30 +02007377#define alc883_dac_nids alc882_dac_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378
Takashi Iwai49535502009-06-30 15:28:30 +02007379/* ADCs */
Kailang Yangdf694da2005-12-05 19:42:22 +01007380#define alc882_adc_nids alc880_adc_nids
7381#define alc882_adc_nids_alt alc880_adc_nids_alt
Takashi Iwai49535502009-06-30 15:28:30 +02007382#define alc883_adc_nids alc882_adc_nids_alt
7383static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 };
7384static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 };
7385#define alc889_adc_nids alc880_adc_nids
Linus Torvalds1da177e2005-04-16 15:20:36 -07007386
Takashi Iwaie1406342008-02-11 18:32:32 +01007387static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 };
7388static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 };
Takashi Iwai49535502009-06-30 15:28:30 +02007389#define alc883_capsrc_nids alc882_capsrc_nids_alt
7390static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 };
7391#define alc889_capsrc_nids alc882_capsrc_nids
Takashi Iwaie1406342008-02-11 18:32:32 +01007392
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393/* input MUX */
7394/* FIXME: should be a matrix-type input source selection */
7395
7396static struct hda_input_mux alc882_capture_source = {
7397 .num_items = 4,
7398 .items = {
7399 { "Mic", 0x0 },
7400 { "Front Mic", 0x1 },
7401 { "Line", 0x2 },
7402 { "CD", 0x4 },
7403 },
7404};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007405
Takashi Iwai49535502009-06-30 15:28:30 +02007406#define alc883_capture_source alc882_capture_source
7407
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007408static struct hda_input_mux alc889_capture_source = {
7409 .num_items = 3,
7410 .items = {
7411 { "Front Mic", 0x0 },
7412 { "Mic", 0x3 },
7413 { "Line", 0x2 },
7414 },
7415};
7416
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007417static struct hda_input_mux mb5_capture_source = {
7418 .num_items = 3,
7419 .items = {
7420 { "Mic", 0x1 },
Alex Murrayb8f171e2010-06-14 12:08:43 +09307421 { "Line", 0x7 },
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007422 { "CD", 0x4 },
7423 },
7424};
7425
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007426static struct hda_input_mux macmini3_capture_source = {
7427 .num_items = 2,
7428 .items = {
7429 { "Line", 0x2 },
7430 { "CD", 0x4 },
7431 },
7432};
7433
Takashi Iwai49535502009-06-30 15:28:30 +02007434static struct hda_input_mux alc883_3stack_6ch_intel = {
7435 .num_items = 4,
7436 .items = {
7437 { "Mic", 0x1 },
7438 { "Front Mic", 0x0 },
7439 { "Line", 0x2 },
7440 { "CD", 0x4 },
7441 },
7442};
7443
7444static struct hda_input_mux alc883_lenovo_101e_capture_source = {
7445 .num_items = 2,
7446 .items = {
7447 { "Mic", 0x1 },
7448 { "Line", 0x2 },
7449 },
7450};
7451
7452static struct hda_input_mux alc883_lenovo_nb0763_capture_source = {
7453 .num_items = 4,
7454 .items = {
7455 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007456 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007457 { "Line", 0x2 },
7458 { "CD", 0x4 },
7459 },
7460};
7461
7462static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = {
7463 .num_items = 2,
7464 .items = {
7465 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +01007466 { "Internal Mic", 0x1 },
Takashi Iwai49535502009-06-30 15:28:30 +02007467 },
7468};
7469
7470static struct hda_input_mux alc883_lenovo_sky_capture_source = {
7471 .num_items = 3,
7472 .items = {
7473 { "Mic", 0x0 },
7474 { "Front Mic", 0x1 },
7475 { "Line", 0x4 },
7476 },
7477};
7478
7479static struct hda_input_mux alc883_asus_eee1601_capture_source = {
7480 .num_items = 2,
7481 .items = {
7482 { "Mic", 0x0 },
7483 { "Line", 0x2 },
7484 },
7485};
7486
7487static struct hda_input_mux alc889A_mb31_capture_source = {
7488 .num_items = 2,
7489 .items = {
7490 { "Mic", 0x0 },
7491 /* Front Mic (0x01) unused */
7492 { "Line", 0x2 },
7493 /* Line 2 (0x03) unused */
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02007494 /* CD (0x04) unused? */
Takashi Iwai49535502009-06-30 15:28:30 +02007495 },
7496};
7497
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007498static struct hda_input_mux alc889A_imac91_capture_source = {
7499 .num_items = 2,
7500 .items = {
7501 { "Mic", 0x01 },
7502 { "Line", 0x2 }, /* Not sure! */
7503 },
7504};
7505
Takashi Iwai49535502009-06-30 15:28:30 +02007506/*
7507 * 2ch mode
7508 */
7509static struct hda_channel_mode alc883_3ST_2ch_modes[1] = {
7510 { 2, NULL }
7511};
7512
Kailang Yangdf694da2005-12-05 19:42:22 +01007513/*
Kailang Yang272a5272007-05-14 11:00:38 +02007514 * 2ch mode
7515 */
7516static struct hda_verb alc882_3ST_ch2_init[] = {
7517 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7518 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7519 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7520 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7521 { } /* end */
7522};
7523
7524/*
Takashi Iwai49535502009-06-30 15:28:30 +02007525 * 4ch mode
7526 */
7527static struct hda_verb alc882_3ST_ch4_init[] = {
7528 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7529 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7530 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7531 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7532 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7533 { } /* end */
7534};
7535
7536/*
Kailang Yang272a5272007-05-14 11:00:38 +02007537 * 6ch mode
7538 */
7539static struct hda_verb alc882_3ST_ch6_init[] = {
7540 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7541 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7542 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7543 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7544 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7545 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7546 { } /* end */
7547};
7548
Takashi Iwai49535502009-06-30 15:28:30 +02007549static struct hda_channel_mode alc882_3ST_6ch_modes[3] = {
Kailang Yang272a5272007-05-14 11:00:38 +02007550 { 2, alc882_3ST_ch2_init },
Takashi Iwai49535502009-06-30 15:28:30 +02007551 { 4, alc882_3ST_ch4_init },
Kailang Yang272a5272007-05-14 11:00:38 +02007552 { 6, alc882_3ST_ch6_init },
7553};
7554
Takashi Iwai49535502009-06-30 15:28:30 +02007555#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes
7556
Kailang Yang272a5272007-05-14 11:00:38 +02007557/*
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04307558 * 2ch mode
7559 */
7560static struct hda_verb alc883_3ST_ch2_clevo_init[] = {
7561 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
7562 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7563 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7564 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7565 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7566 { } /* end */
7567};
7568
7569/*
7570 * 4ch mode
7571 */
7572static struct hda_verb alc883_3ST_ch4_clevo_init[] = {
7573 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7574 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7575 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7576 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7577 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7578 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7579 { } /* end */
7580};
7581
7582/*
7583 * 6ch mode
7584 */
7585static struct hda_verb alc883_3ST_ch6_clevo_init[] = {
7586 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7587 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7588 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7589 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7590 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7591 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7592 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7593 { } /* end */
7594};
7595
7596static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = {
7597 { 2, alc883_3ST_ch2_clevo_init },
7598 { 4, alc883_3ST_ch4_clevo_init },
7599 { 6, alc883_3ST_ch6_clevo_init },
7600};
7601
7602
7603/*
Kailang Yangdf694da2005-12-05 19:42:22 +01007604 * 6ch mode
7605 */
7606static struct hda_verb alc882_sixstack_ch6_init[] = {
7607 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7608 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7609 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7610 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7611 { } /* end */
7612};
7613
7614/*
7615 * 8ch mode
7616 */
7617static struct hda_verb alc882_sixstack_ch8_init[] = {
7618 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7619 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7620 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7621 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7622 { } /* end */
7623};
7624
7625static struct hda_channel_mode alc882_sixstack_modes[2] = {
7626 { 6, alc882_sixstack_ch6_init },
7627 { 8, alc882_sixstack_ch8_init },
7628};
7629
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007630
7631/* Macbook Air 2,1 */
7632
7633static struct hda_channel_mode alc885_mba21_ch_modes[1] = {
7634 { 2, NULL },
7635};
7636
Takashi Iwai87350ad2007-08-16 18:19:38 +02007637/*
Sasha Alexandrdef319f2009-06-16 16:00:15 -04007638 * macbook pro ALC885 can switch LineIn to LineOut without losing Mic
Takashi Iwai87350ad2007-08-16 18:19:38 +02007639 */
7640
7641/*
7642 * 2ch mode
7643 */
7644static struct hda_verb alc885_mbp_ch2_init[] = {
7645 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7646 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
7647 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
7648 { } /* end */
7649};
7650
7651/*
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007652 * 4ch mode
Takashi Iwai87350ad2007-08-16 18:19:38 +02007653 */
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007654static struct hda_verb alc885_mbp_ch4_init[] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007655 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7656 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7657 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7658 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
7659 { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
7660 { } /* end */
7661};
7662
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007663static struct hda_channel_mode alc885_mbp_4ch_modes[2] = {
Takashi Iwai87350ad2007-08-16 18:19:38 +02007664 { 2, alc885_mbp_ch2_init },
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007665 { 4, alc885_mbp_ch4_init },
Takashi Iwai87350ad2007-08-16 18:19:38 +02007666};
7667
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007668/*
7669 * 2ch
7670 * Speakers/Woofer/HP = Front
7671 * LineIn = Input
7672 */
7673static struct hda_verb alc885_mb5_ch2_init[] = {
7674 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
7675 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
7676 { } /* end */
7677};
7678
7679/*
7680 * 6ch mode
7681 * Speakers/HP = Front
7682 * Woofer = LFE
7683 * LineIn = Surround
7684 */
7685static struct hda_verb alc885_mb5_ch6_init[] = {
7686 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
7687 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
7688 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
7689 { } /* end */
7690};
7691
7692static struct hda_channel_mode alc885_mb5_6ch_modes[2] = {
7693 { 2, alc885_mb5_ch2_init },
7694 { 6, alc885_mb5_ch6_init },
7695};
Takashi Iwai87350ad2007-08-16 18:19:38 +02007696
Takashi Iwaid01aecd2010-02-23 08:07:15 +01007697#define alc885_macmini3_6ch_modes alc885_mb5_6ch_modes
Takashi Iwai49535502009-06-30 15:28:30 +02007698
7699/*
7700 * 2ch mode
7701 */
7702static struct hda_verb alc883_4ST_ch2_init[] = {
7703 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7704 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7705 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7706 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7707 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7708 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7709 { } /* end */
7710};
7711
7712/*
7713 * 4ch mode
7714 */
7715static struct hda_verb alc883_4ST_ch4_init[] = {
7716 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7717 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7718 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7719 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7720 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7721 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7722 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7723 { } /* end */
7724};
7725
7726/*
7727 * 6ch mode
7728 */
7729static struct hda_verb alc883_4ST_ch6_init[] = {
7730 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7731 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7732 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7733 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7734 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7735 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7736 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7737 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7738 { } /* end */
7739};
7740
7741/*
7742 * 8ch mode
7743 */
7744static struct hda_verb alc883_4ST_ch8_init[] = {
7745 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7746 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7747 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7748 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7749 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7750 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
7751 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7752 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7753 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7754 { } /* end */
7755};
7756
7757static struct hda_channel_mode alc883_4ST_8ch_modes[4] = {
7758 { 2, alc883_4ST_ch2_init },
7759 { 4, alc883_4ST_ch4_init },
7760 { 6, alc883_4ST_ch6_init },
7761 { 8, alc883_4ST_ch8_init },
7762};
7763
7764
7765/*
7766 * 2ch mode
7767 */
7768static struct hda_verb alc883_3ST_ch2_intel_init[] = {
7769 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7770 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7771 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7772 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7773 { } /* end */
7774};
7775
7776/*
7777 * 4ch mode
7778 */
7779static struct hda_verb alc883_3ST_ch4_intel_init[] = {
7780 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
7781 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7782 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7783 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7784 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7785 { } /* end */
7786};
7787
7788/*
7789 * 6ch mode
7790 */
7791static struct hda_verb alc883_3ST_ch6_intel_init[] = {
7792 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7793 { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7794 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 },
7795 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7796 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
7797 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
7798 { } /* end */
7799};
7800
7801static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = {
7802 { 2, alc883_3ST_ch2_intel_init },
7803 { 4, alc883_3ST_ch4_intel_init },
7804 { 6, alc883_3ST_ch6_intel_init },
7805};
7806
7807/*
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007808 * 2ch mode
7809 */
7810static struct hda_verb alc889_ch2_intel_init[] = {
7811 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7812 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x00 },
7813 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x00 },
7814 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x00 },
7815 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
7816 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7817 { } /* end */
7818};
7819
7820/*
Takashi Iwai49535502009-06-30 15:28:30 +02007821 * 6ch mode
7822 */
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007823static struct hda_verb alc889_ch6_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007824 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7825 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7826 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7827 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7828 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007829 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
7830 { } /* end */
7831};
7832
7833/*
7834 * 8ch mode
7835 */
7836static struct hda_verb alc889_ch8_intel_init[] = {
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007837 { 0x14, AC_VERB_SET_CONNECT_SEL, 0x00 },
7838 { 0x19, AC_VERB_SET_CONNECT_SEL, 0x01 },
7839 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x02 },
7840 { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 },
7841 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x03 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007842 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7843 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007844 { } /* end */
7845};
7846
Wu Fengguangdd7714c2009-07-30 14:36:35 +08007847static struct hda_channel_mode alc889_8ch_intel_modes[3] = {
7848 { 2, alc889_ch2_intel_init },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02007849 { 6, alc889_ch6_intel_init },
7850 { 8, alc889_ch8_intel_init },
7851};
7852
7853/*
7854 * 6ch mode
7855 */
Takashi Iwai49535502009-06-30 15:28:30 +02007856static struct hda_verb alc883_sixstack_ch6_init[] = {
7857 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
7858 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7859 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7860 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7861 { } /* end */
7862};
7863
7864/*
7865 * 8ch mode
7866 */
7867static struct hda_verb alc883_sixstack_ch8_init[] = {
7868 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7869 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7870 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7871 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
7872 { } /* end */
7873};
7874
7875static struct hda_channel_mode alc883_sixstack_modes[2] = {
7876 { 6, alc883_sixstack_ch6_init },
7877 { 8, alc883_sixstack_ch8_init },
7878};
7879
7880
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
7882 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
7883 */
Takashi Iwaic8b6bf9b2005-11-17 14:57:47 +01007884static struct snd_kcontrol_new alc882_base_mixer[] = {
Takashi Iwai05acb862005-06-10 19:50:25 +02007885 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007886 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007887 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007888 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007889 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
7890 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007891 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
7892 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Takashi Iwai05acb862005-06-10 19:50:25 +02007893 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai985be542005-11-02 18:26:49 +01007894 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007895 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7896 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7897 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7898 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7899 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7900 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007901 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007902 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
7903 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007904 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007905 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -07007906 { } /* end */
7907};
7908
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08007909/* Macbook Air 2,1 same control for HP and internal Speaker */
7910
7911static struct snd_kcontrol_new alc885_mba21_mixer[] = {
7912 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7913 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_OUTPUT),
7914 { }
7915};
7916
7917
Takashi Iwai87350ad2007-08-16 18:19:38 +02007918static struct snd_kcontrol_new alc885_mbp3_mixer[] = {
Takashi Iwaia3f730a2009-08-31 08:15:26 +02007919 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7920 HDA_BIND_MUTE ("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
7921 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7922 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0e, 0x02, HDA_INPUT),
7923 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
Takashi Iwai2134ea42008-01-10 16:53:55 +01007924 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7925 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007926 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
7927 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007928 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
7929 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
Takashi Iwai87350ad2007-08-16 18:19:38 +02007930 { } /* end */
7931};
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007932
7933static struct snd_kcontrol_new alc885_mb5_mixer[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007934 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7935 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7936 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7937 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7938 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7939 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
Alex Murraya76221d2010-01-13 23:15:03 +10307940 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7941 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
Alex Murrayb8f171e2010-06-14 12:08:43 +09307942 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7943 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007944 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
7945 HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007946 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
7947 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0x00, HDA_INPUT),
Kacper Szczesniak41d55452009-05-07 12:47:43 +02007948 { } /* end */
7949};
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02007950
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007951static struct snd_kcontrol_new alc885_macmini3_mixer[] = {
7952 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7953 HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
7954 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
7955 HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
7956 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT),
7957 HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT),
7958 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0f, 0x00, HDA_OUTPUT),
7959 HDA_BIND_MUTE ("Headphone Playback Switch", 0x0f, 0x02, HDA_INPUT),
7960 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x07, HDA_INPUT),
7961 HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x07, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007962 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x00, HDA_INPUT),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11007963 { } /* end */
7964};
7965
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007966static struct snd_kcontrol_new alc885_imac91_mixer[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07007967 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
7968 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 0x02, HDA_INPUT),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08007969 { } /* end */
7970};
7971
7972
Kailang Yangbdd148a2007-05-08 15:19:08 +02007973static struct snd_kcontrol_new alc882_w2jc_mixer[] = {
7974 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7975 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7976 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7977 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7978 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7979 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7980 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007981 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007982 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +02007983 { } /* end */
7984};
7985
Kailang Yang272a5272007-05-14 11:00:38 +02007986static struct snd_kcontrol_new alc882_targa_mixer[] = {
7987 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
7988 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
7989 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
7990 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
7991 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
7992 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
7993 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
7994 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
7995 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007996 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02007997 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
7998 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01007999 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008000 { } /* end */
8001};
8002
8003/* Pin assignment: Front=0x14, HP = 0x15, Front = 0x16, ???
8004 * Front Mic=0x18, Line In = 0x1a, Line In = 0x1b, CD = 0x1c
8005 */
8006static struct snd_kcontrol_new alc882_asus_a7j_mixer[] = {
8007 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8008 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
8009 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8010 HDA_CODEC_MUTE("Mobile Front Playback Switch", 0x16, 0x0, HDA_OUTPUT),
8011 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8012 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8013 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8014 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8015 HDA_CODEC_VOLUME("Mobile Line Playback Volume", 0x0b, 0x03, HDA_INPUT),
8016 HDA_CODEC_MUTE("Mobile Line Playback Switch", 0x0b, 0x03, HDA_INPUT),
8017 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
8018 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008019 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02008020 { } /* end */
8021};
8022
Takashi Iwai914759b2007-09-06 14:52:04 +02008023static struct snd_kcontrol_new alc882_asus_a7m_mixer[] = {
8024 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8025 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8026 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8027 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8028 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8029 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8030 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8031 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008032 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008033 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwai914759b2007-09-06 14:52:04 +02008034 { } /* end */
8035};
8036
Kailang Yangdf694da2005-12-05 19:42:22 +01008037static struct snd_kcontrol_new alc882_chmode_mixer[] = {
8038 {
8039 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8040 .name = "Channel Mode",
8041 .info = alc_ch_mode_info,
8042 .get = alc_ch_mode_get,
8043 .put = alc_ch_mode_put,
8044 },
8045 { } /* end */
8046};
8047
Takashi Iwai49535502009-06-30 15:28:30 +02008048static struct hda_verb alc882_base_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008049 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008050 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8051 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008052 /* Rear mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008053 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8054 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008055 /* CLFE mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008056 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8057 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008058 /* Side mixer */
Takashi Iwai05acb862005-06-10 19:50:25 +02008059 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8060 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008061
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008062 /* Front Pin: output 0 (0x0c) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008063 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008064 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008065 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008066 /* Rear Pin: output 1 (0x0d) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008067 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008068 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008069 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008070 /* CLFE Pin: output 2 (0x0e) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008071 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008072 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008073 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008074 /* Side Pin: output 3 (0x0f) */
Takashi Iwai05acb862005-06-10 19:50:25 +02008075 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai05acb862005-06-10 19:50:25 +02008076 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008077 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008078 /* Mic (rear) pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008079 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008080 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8081 /* Front Mic pin: input vref at 80% */
Takashi Iwai16ded522005-06-10 19:58:24 +02008082 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008083 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8084 /* Line In pin: input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008085 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaie9edcee2005-06-13 14:16:38 +02008086 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8087 /* Line-2 In: Headphone output (output 0 - 0x0c) */
8088 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8089 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8090 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008091 /* CD pin widget for input */
Takashi Iwai05acb862005-06-10 19:50:25 +02008092 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008093
8094 /* FIXME: use matrix-type input source selection */
8095 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008096 /* Input mixer2 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008097 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008098 /* Input mixer3 */
Takashi Iwai05acb862005-06-10 19:50:25 +02008099 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai05acb862005-06-10 19:50:25 +02008100 /* ADC2: mute amp left and right */
8101 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008102 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwai05acb862005-06-10 19:50:25 +02008103 /* ADC3: mute amp left and right */
8104 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Takashi Iwai71fe7b82005-05-25 18:11:40 +02008105 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Linus Torvalds1da177e2005-04-16 15:20:36 -07008106
8107 { }
8108};
8109
Takashi Iwai49535502009-06-30 15:28:30 +02008110static struct hda_verb alc882_adc1_init_verbs[] = {
8111 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8112 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8113 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8114 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8115 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8116 /* ADC1: mute amp left and right */
8117 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8118 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8119 { }
8120};
8121
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008122static struct hda_verb alc882_eapd_verbs[] = {
8123 /* change to EAPD mode */
8124 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008125 {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008126 { }
Takashi Iwai4b146cb2006-07-28 14:42:36 +02008127};
8128
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008129static struct hda_verb alc889_eapd_verbs[] = {
8130 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
8131 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
8132 { }
8133};
8134
Wu Fengguang6732bd02009-07-30 09:19:14 +02008135static struct hda_verb alc_hp15_unsol_verbs[] = {
8136 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
8137 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8138 {}
8139};
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008140
8141static struct hda_verb alc885_init_verbs[] = {
8142 /* Front mixer: unmute input/output amp left and right (volume = 0) */
Kailang Yang88102f32010-02-04 14:12:58 +01008143 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8144 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008145 /* Rear mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008146 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8147 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008148 /* CLFE mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008149 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8150 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008151 /* Side mixer */
Kailang Yang88102f32010-02-04 14:12:58 +01008152 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8153 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008154
8155 /* Front HP Pin: output 0 (0x0c) */
Wu Fengguang6732bd02009-07-30 09:19:14 +02008156 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008157 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8158 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8159 /* Front Pin: output 0 (0x0c) */
8160 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8161 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8162 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8163 /* Rear Pin: output 1 (0x0d) */
8164 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8165 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8166 {0x19, AC_VERB_SET_CONNECT_SEL, 0x01},
8167 /* CLFE Pin: output 2 (0x0e) */
8168 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8169 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8170 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
8171 /* Side Pin: output 3 (0x0f) */
8172 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8173 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8174 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
8175 /* Mic (rear) pin: input vref at 80% */
8176 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8177 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8178 /* Front Mic pin: input vref at 80% */
8179 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8180 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8181 /* Line In pin: input */
8182 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8183 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8184
8185 /* Mixer elements: 0x18, , 0x1a, 0x1b */
8186 /* Input mixer1 */
Kailang Yang88102f32010-02-04 14:12:58 +01008187 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008188 /* Input mixer2 */
8189 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008190 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008191 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008192 /* ADC2: mute amp left and right */
8193 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8194 /* ADC3: mute amp left and right */
8195 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8196
8197 { }
8198};
8199
8200static struct hda_verb alc885_init_input_verbs[] = {
8201 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8202 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
8203 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
8204 { }
8205};
8206
8207
8208/* Unmute Selector 24h and set the default input to front mic */
8209static struct hda_verb alc889_init_input_verbs[] = {
8210 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
8211 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8212 { }
8213};
8214
8215
Takashi Iwai49535502009-06-30 15:28:30 +02008216#define alc883_init_verbs alc882_base_init_verbs
8217
Tobin Davis9102cd12006-12-15 10:02:12 +01008218/* Mac Pro test */
8219static struct snd_kcontrol_new alc882_macpro_mixer[] = {
8220 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8221 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8222 HDA_CODEC_MUTE("Headphone Playback Switch", 0x18, 0x0, HDA_OUTPUT),
8223 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
8224 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008225 /* FIXME: this looks suspicious...
Jaroslav Kyselad355c82a2009-11-03 15:47:25 +01008226 HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT),
8227 HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT),
Takashi Iwai45bdd1c2009-02-06 16:11:25 +01008228 */
Tobin Davis9102cd12006-12-15 10:02:12 +01008229 { } /* end */
8230};
8231
8232static struct hda_verb alc882_macpro_init_verbs[] = {
8233 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8234 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8235 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8236 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8237 /* Front Pin: output 0 (0x0c) */
8238 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8239 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8240 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
8241 /* Front Mic pin: input vref at 80% */
8242 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8243 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8244 /* Speaker: output */
8245 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8246 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8247 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x04},
8248 /* Headphone output (output 0 - 0x0c) */
8249 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8250 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8251 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8252
8253 /* FIXME: use matrix-type input source selection */
8254 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8255 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8256 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8257 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8258 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8259 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8260 /* Input mixer2 */
8261 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8262 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8263 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8264 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8265 /* Input mixer3 */
8266 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8267 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8268 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8269 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8270 /* ADC1: mute amp left and right */
8271 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8272 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8273 /* ADC2: mute amp left and right */
8274 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8275 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8276 /* ADC3: mute amp left and right */
8277 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8278 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8279
8280 { }
8281};
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008282
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008283/* Macbook 5,1 */
8284static struct hda_verb alc885_mb5_init_verbs[] = {
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008285 /* DACs */
8286 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8287 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8288 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8289 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008290 /* Front mixer */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008291 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8292 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8293 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008294 /* Surround mixer */
8295 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8296 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8297 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8298 /* LFE mixer */
8299 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8300 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8301 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8302 /* HP mixer */
8303 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8304 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8305 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8306 /* Front Pin (0x0c) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008307 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8308 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008309 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8310 /* LFE Pin (0x0e) */
8311 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8312 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8313 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8314 /* HP Pin (0x0f) */
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008315 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8316 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kacper Szczesniak92b9de82009-06-02 00:55:19 +02008317 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
Alex Murraya76221d2010-01-13 23:15:03 +10308318 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008319 /* Front Mic pin: input vref at 80% */
8320 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8321 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8322 /* Line In pin */
8323 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8324 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8325
Alex Murrayb8f171e2010-06-14 12:08:43 +09308326 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0x1)},
8327 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x7)},
8328 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0x4)},
Kacper Szczesniak41d55452009-05-07 12:47:43 +02008329 { }
8330};
8331
Luke Yelaviche458b1f2010-02-12 16:28:29 +11008332/* Macmini 3,1 */
8333static struct hda_verb alc885_macmini3_init_verbs[] = {
8334 /* DACs */
8335 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8336 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8337 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8338 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8339 /* Front mixer */
8340 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8341 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8342 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8343 /* Surround mixer */
8344 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8345 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8346 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8347 /* LFE mixer */
8348 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8349 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8350 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8351 /* HP mixer */
8352 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8353 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8354 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8355 /* Front Pin (0x0c) */
8356 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8357 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8358 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8359 /* LFE Pin (0x0e) */
8360 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01},
8361 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8362 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02},
8363 /* HP Pin (0x0f) */
8364 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8365 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8366 {0x14, AC_VERB_SET_CONNECT_SEL, 0x03},
8367 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8368 /* Line In pin */
8369 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8370 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8371
8372 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8373 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8374 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8375 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8376 { }
8377};
8378
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008379
8380static struct hda_verb alc885_mba21_init_verbs[] = {
8381 /*Internal and HP Speaker Mixer*/
8382 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8383 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8384 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8385 /*Internal Speaker Pin (0x0c)*/
8386 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8387 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8388 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8389 /* HP Pin: output 0 (0x0e) */
8390 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
8391 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8392 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8393 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8394 /* Line in (is hp when jack connected)*/
8395 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8396 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8397
8398 { }
8399 };
8400
8401
Takashi Iwai87350ad2007-08-16 18:19:38 +02008402/* Macbook Pro rev3 */
8403static struct hda_verb alc885_mbp3_init_verbs[] = {
8404 /* Front mixer: unmute input/output amp left and right (volume = 0) */
8405 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8406 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8407 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8408 /* Rear mixer */
8409 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8410 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8411 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008412 /* HP mixer */
8413 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8414 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8415 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008416 /* Front Pin: output 0 (0x0c) */
8417 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8418 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8419 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008420 /* HP Pin: output 0 (0x0e) */
Takashi Iwai87350ad2007-08-16 18:19:38 +02008421 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4},
Takashi Iwaia3f730a2009-08-31 08:15:26 +02008422 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8423 {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},
Takashi Iwai87350ad2007-08-16 18:19:38 +02008424 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8425 /* Mic (rear) pin: input vref at 80% */
8426 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8427 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8428 /* Front Mic pin: input vref at 80% */
8429 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8430 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8431 /* Line In pin: use output 1 when in LineOut mode */
8432 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
8433 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8434 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
8435
8436 /* FIXME: use matrix-type input source selection */
8437 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
8438 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
8439 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8440 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8441 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8442 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8443 /* Input mixer2 */
8444 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8445 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8446 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8447 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8448 /* Input mixer3 */
8449 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8450 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8451 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8452 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
8453 /* ADC1: mute amp left and right */
8454 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8455 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
8456 /* ADC2: mute amp left and right */
8457 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8458 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8459 /* ADC3: mute amp left and right */
8460 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8461 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8462
8463 { }
8464};
8465
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008466/* iMac 9,1 */
8467static struct hda_verb alc885_imac91_init_verbs[] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008468 /* Internal Speaker Pin (0x0c) */
8469 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8470 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8471 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8472 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, (PIN_OUT | AC_PINCTL_VREF_50) },
8473 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8474 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8475 /* HP Pin: Rear */
8476 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8477 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8478 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8479 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, (ALC880_HP_EVENT | AC_USRSP_EN)},
8480 /* Line in Rear */
8481 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_VREF_50},
8482 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8483 /* Front Mic pin: input vref at 80% */
8484 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8485 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008486 /* Rear mixer */
8487 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8488 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8489 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008490 /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */
8491 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8492 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8493 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
8494 /* 0x24 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008495 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8496 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8497 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8498 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008499 /* 0x23 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008500 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8501 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8502 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8503 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008504 /* 0x22 [Audio Mixer] wcaps 0x20010b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008505 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8506 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
8507 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
8508 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008509 /* 0x07 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008510 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8511 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008512 /* 0x08 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008513 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8514 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008515 /* 0x09 [Audio Input] wcaps 0x10011b: Stereo Amp-In */
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008516 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
8517 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008518 { }
8519};
8520
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008521/* iMac 24 mixer. */
8522static struct snd_kcontrol_new alc885_imac24_mixer[] = {
8523 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
8524 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
8525 { } /* end */
8526};
8527
8528/* iMac 24 init verbs. */
8529static struct hda_verb alc885_imac24_init_verbs[] = {
8530 /* Internal speakers: output 0 (0x0c) */
8531 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8532 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8533 {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
8534 /* Internal speakers: output 0 (0x0c) */
8535 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8536 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8537 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
8538 /* Headphone: output 0 (0x0c) */
8539 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8540 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
8541 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
8542 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
8543 /* Front Mic: input vref at 80% */
8544 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
8545 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
8546 { }
8547};
8548
8549/* Toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008550static void alc885_imac24_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008551{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008552 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008553
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008554 spec->autocfg.hp_pins[0] = 0x14;
8555 spec->autocfg.speaker_pins[0] = 0x18;
8556 spec->autocfg.speaker_pins[1] = 0x1a;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008557}
8558
Takashi Iwai9d54f082010-02-22 08:34:40 +01008559#define alc885_mb5_setup alc885_imac24_setup
8560#define alc885_macmini3_setup alc885_imac24_setup
8561
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08008562/* Macbook Air 2,1 */
8563static void alc885_mba21_setup(struct hda_codec *codec)
8564{
8565 struct alc_spec *spec = codec->spec;
8566
8567 spec->autocfg.hp_pins[0] = 0x14;
8568 spec->autocfg.speaker_pins[0] = 0x18;
8569}
8570
8571
8572
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008573static void alc885_mbp3_setup(struct hda_codec *codec)
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008574{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008575 struct alc_spec *spec = codec->spec;
Nicola Fagnanic54728d2007-07-19 23:28:52 +02008576
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008577 spec->autocfg.hp_pins[0] = 0x15;
8578 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai87350ad2007-08-16 18:19:38 +02008579}
8580
Takashi Iwai9d54f082010-02-22 08:34:40 +01008581static void alc885_imac91_setup(struct hda_codec *codec)
Alex Murraya76221d2010-01-13 23:15:03 +10308582{
Takashi Iwai9d54f082010-02-22 08:34:40 +01008583 struct alc_spec *spec = codec->spec;
Alex Murraya76221d2010-01-13 23:15:03 +10308584
Takashi Iwai9d54f082010-02-22 08:34:40 +01008585 spec->autocfg.hp_pins[0] = 0x14;
Justin P. Mattockb7cccc52010-05-23 10:55:00 -07008586 spec->autocfg.speaker_pins[0] = 0x18;
Takashi Iwai9d54f082010-02-22 08:34:40 +01008587 spec->autocfg.speaker_pins[1] = 0x1a;
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08008588}
Takashi Iwai87350ad2007-08-16 18:19:38 +02008589
Kailang Yang272a5272007-05-14 11:00:38 +02008590static struct hda_verb alc882_targa_verbs[] = {
8591 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8592 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8593
8594 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8595 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008596
Kailang Yang272a5272007-05-14 11:00:38 +02008597 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8598 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8599 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8600
8601 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yang272a5272007-05-14 11:00:38 +02008602 { } /* end */
8603};
8604
8605/* toggle speaker-output according to the hp-jack state */
8606static void alc882_targa_automute(struct hda_codec *codec)
8607{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008608 struct alc_spec *spec = codec->spec;
8609 alc_automute_amp(codec);
Takashi Iwai82beb8f2007-08-10 17:09:26 +02008610 snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008611 spec->jack_present ? 1 : 3);
8612}
8613
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008614static void alc882_targa_setup(struct hda_codec *codec)
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008615{
8616 struct alc_spec *spec = codec->spec;
8617
8618 spec->autocfg.hp_pins[0] = 0x14;
8619 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang272a5272007-05-14 11:00:38 +02008620}
8621
8622static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res)
8623{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02008624 if ((res >> 26) == ALC880_HP_EVENT)
Kailang Yang272a5272007-05-14 11:00:38 +02008625 alc882_targa_automute(codec);
Kailang Yang272a5272007-05-14 11:00:38 +02008626}
8627
8628static struct hda_verb alc882_asus_a7j_verbs[] = {
8629 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8630 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8631
8632 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8633 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8634 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008635
Kailang Yang272a5272007-05-14 11:00:38 +02008636 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8637 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8638 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8639
8640 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8641 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8642 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8643 { } /* end */
8644};
8645
Takashi Iwai914759b2007-09-06 14:52:04 +02008646static struct hda_verb alc882_asus_a7m_verbs[] = {
8647 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8648 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8649
8650 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
8651 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
8652 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02008653
Takashi Iwai914759b2007-09-06 14:52:04 +02008654 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8655 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8656 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front */
8657
8658 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
8659 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */
8660 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
8661 { } /* end */
8662};
8663
Tobin Davis9102cd12006-12-15 10:02:12 +01008664static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
8665{
8666 unsigned int gpiostate, gpiomask, gpiodir;
8667
8668 gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
8669 AC_VERB_GET_GPIO_DATA, 0);
8670
8671 if (!muted)
8672 gpiostate |= (1 << pin);
8673 else
8674 gpiostate &= ~(1 << pin);
8675
8676 gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
8677 AC_VERB_GET_GPIO_MASK, 0);
8678 gpiomask |= (1 << pin);
8679
8680 gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
8681 AC_VERB_GET_GPIO_DIRECTION, 0);
8682 gpiodir |= (1 << pin);
8683
8684
8685 snd_hda_codec_write(codec, codec->afg, 0,
8686 AC_VERB_SET_GPIO_MASK, gpiomask);
8687 snd_hda_codec_write(codec, codec->afg, 0,
8688 AC_VERB_SET_GPIO_DIRECTION, gpiodir);
8689
8690 msleep(1);
8691
8692 snd_hda_codec_write(codec, codec->afg, 0,
8693 AC_VERB_SET_GPIO_DATA, gpiostate);
8694}
8695
Takashi Iwai7debbe52007-08-16 15:01:03 +02008696/* set up GPIO at initialization */
8697static void alc885_macpro_init_hook(struct hda_codec *codec)
8698{
8699 alc882_gpio_mute(codec, 0, 0);
8700 alc882_gpio_mute(codec, 1, 0);
8701}
8702
8703/* set up GPIO and update auto-muting at initialization */
8704static void alc885_imac24_init_hook(struct hda_codec *codec)
8705{
8706 alc885_macpro_init_hook(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +02008707 alc_automute_amp(codec);
Takashi Iwai7debbe52007-08-16 15:01:03 +02008708}
8709
Kailang Yangdf694da2005-12-05 19:42:22 +01008710/*
8711 * generic initialization of ADC, input mixers and output mixers
8712 */
Takashi Iwai49535502009-06-30 15:28:30 +02008713static struct hda_verb alc883_auto_init_verbs[] = {
Kailang Yangdf694da2005-12-05 19:42:22 +01008714 /*
8715 * Unmute ADC0-2 and set the default input to mic-in
8716 */
Kailang Yangdf694da2005-12-05 19:42:22 +01008717 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
8718 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8719 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
8720 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8721
Kailang Yangdf694da2005-12-05 19:42:22 +01008722 /*
8723 * Set up output mixers (0x0c - 0x0f)
8724 */
8725 /* set vol=0 to output mixers */
8726 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8727 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8728 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8729 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
8730 /* set up input amps for analog loopback */
8731 /* Amp Indices: DAC = 0, mixer = 1 */
8732 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8733 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8734 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8735 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8736 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8737 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8738 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8739 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8740 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
8741 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
8742
8743 /* FIXME: use matrix-type input source selection */
8744 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
Kailang Yangdf694da2005-12-05 19:42:22 +01008745 /* Input mixer2 */
Kailang Yang88102f32010-02-04 14:12:58 +01008746 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008747 /* Input mixer3 */
Kailang Yang88102f32010-02-04 14:12:58 +01008748 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangdf694da2005-12-05 19:42:22 +01008749 { }
8750};
8751
Torben Schulzeb4c41d2009-05-18 15:02:35 +02008752/* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */
8753static struct hda_verb alc889A_mb31_ch2_init[] = {
8754 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8755 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8756 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8757 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8758 { } /* end */
8759};
8760
8761/* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */
8762static struct hda_verb alc889A_mb31_ch4_init[] = {
8763 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */
8764 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8765 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8766 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8767 { } /* end */
8768};
8769
8770/* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */
8771static struct hda_verb alc889A_mb31_ch5_init[] = {
8772 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */
8773 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */
8774 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */
8775 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */
8776 { } /* end */
8777};
8778
8779/* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */
8780static struct hda_verb alc889A_mb31_ch6_init[] = {
8781 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */
8782 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */
8783 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */
8784 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */
8785 { } /* end */
8786};
8787
8788static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = {
8789 { 2, alc889A_mb31_ch2_init },
8790 { 4, alc889A_mb31_ch4_init },
8791 { 5, alc889A_mb31_ch5_init },
8792 { 6, alc889A_mb31_ch6_init },
8793};
8794
Andrew L. Neporadab373bde2006-11-07 11:37:08 +01008795static struct hda_verb alc883_medion_eapd_verbs[] = {
8796 /* eanable EAPD on medion laptop */
8797 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
8798 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
8799 { }
8800};
8801
Takashi Iwai49535502009-06-30 15:28:30 +02008802#define alc883_base_mixer alc882_base_mixer
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008803
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008804static struct snd_kcontrol_new alc883_mitac_mixer[] = {
8805 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8806 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8807 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8808 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8809 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8810 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8811 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8812 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008813 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008814 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8815 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008816 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008817 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01008818 { } /* end */
8819};
8820
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01008821static struct snd_kcontrol_new alc883_clevo_m720_mixer[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01008822 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8823 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8824 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8825 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8826 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008827 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008828 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008829 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008830 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008831 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe368c7a92008-03-04 11:20:33 +01008832 { } /* end */
8833};
8834
Jiang zhefb97dc62008-03-06 11:07:11 +01008835static struct snd_kcontrol_new alc883_2ch_fujitsu_pi2515_mixer[] = {
8836 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8837 HDA_BIND_MUTE("Headphone Playback Switch", 0x0c, 2, HDA_INPUT),
8838 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8839 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
8840 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008841 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008842 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008843 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008844 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008845 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhefb97dc62008-03-06 11:07:11 +01008846 { } /* end */
8847};
8848
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008849static struct snd_kcontrol_new alc883_3ST_2ch_mixer[] = {
8850 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8851 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8852 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8853 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8854 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8855 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8856 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8857 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008858 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008859 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8860 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008861 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008862 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008863 { } /* end */
8864};
8865
8866static struct snd_kcontrol_new alc883_3ST_6ch_mixer[] = {
8867 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8868 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8869 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8870 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8871 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8872 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8873 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8874 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8875 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8876 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8877 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8878 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8879 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8880 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008881 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008882 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8883 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008884 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008885 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +02008886 { } /* end */
8887};
8888
Jiang zhe17bba1b2008-06-04 12:11:07 +02008889static struct snd_kcontrol_new alc883_3ST_6ch_intel_mixer[] = {
8890 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8891 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8892 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8893 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8894 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8895 HDA_OUTPUT),
8896 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8897 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8898 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8899 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8900 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8901 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8902 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8903 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8904 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008905 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008906 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
8907 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008908 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008909 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Jiang zhe17bba1b2008-06-04 12:11:07 +02008910 { } /* end */
8911};
8912
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008913static struct snd_kcontrol_new alc885_8ch_intel_mixer[] = {
8914 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
8915 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
8916 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8917 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8918 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0,
8919 HDA_OUTPUT),
8920 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8921 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8922 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8923 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8924 HDA_BIND_MUTE("Speaker Playback Switch", 0x0f, 2, HDA_INPUT),
8925 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
8926 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8927 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8928 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x3, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008929 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008930 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x3, HDA_INPUT),
8931 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008932 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02008933 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8934 { } /* end */
8935};
8936
Takashi Iwaid1d985f2006-11-23 19:27:12 +01008937static struct snd_kcontrol_new alc883_fivestack_mixer[] = {
Tobin Davisc07584c2006-10-13 12:32:16 +02008938 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008939 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008940 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008941 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008942 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8943 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
Takashi Iwai0701e062008-06-27 16:30:57 +02008944 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8945 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008946 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
8947 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8948 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8949 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8950 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8951 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008952 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008953 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
8954 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008955 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008956 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Tobin Davisc07584c2006-10-13 12:32:16 +02008957 { } /* end */
8958};
8959
Sasha Alexandrc2592492009-06-16 14:52:54 -04008960static struct snd_kcontrol_new alc883_targa_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008961 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008962 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008963 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008964 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008965 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
8966 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
8967 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
8968 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
8969 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
8970 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
8971 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8972 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8973 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
8974 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
8975 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008976 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008977 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008978 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008979};
Kailang Yangccc656c2006-10-17 12:32:26 +02008980
Sasha Alexandrc2592492009-06-16 14:52:54 -04008981static struct snd_kcontrol_new alc883_targa_2ch_mixer[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02008982 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008983 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008984 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02008985 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008986 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
8987 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
8988 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008989 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008990 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008991 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01008992 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01008993 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangccc656c2006-10-17 12:32:26 +02008994 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02008995};
Kailang Yangccc656c2006-10-17 12:32:26 +02008996
Takashi Iwaib99dba32009-09-17 18:23:00 +02008997static struct snd_kcontrol_new alc883_targa_8ch_mixer[] = {
8998 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
8999 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009000 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009001 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009002 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwaib99dba32009-09-17 18:23:00 +02009003 { } /* end */
9004};
9005
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009006static struct snd_kcontrol_new alc883_lenovo_101e_2ch_mixer[] = {
9007 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9008 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +01009009 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
9010 HDA_BIND_MUTE("Speaker Playback Switch", 0x0d, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009011 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
9012 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009013 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009014 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009015 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +02009016};
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009017
Kailang Yang272a5272007-05-14 11:00:38 +02009018static struct snd_kcontrol_new alc883_lenovo_nb0763_mixer[] = {
9019 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9020 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
9021 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9022 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9023 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9024 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
9025 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +01009026 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
9027 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +02009028 { } /* end */
9029};
9030
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009031static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
9032 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9033 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9034 HDA_CODEC_MUTE("Speaker Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9035 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
9036 HDA_CODEC_VOLUME("Line Playback Volume", 0x08, 0x0, HDA_INPUT),
9037 HDA_CODEC_MUTE("Line Playback Switch", 0x08, 0x0, HDA_INPUT),
9038 { } /* end */
9039};
9040
9041static struct hda_verb alc883_medion_wim2160_verbs[] = {
9042 /* Unmute front mixer */
9043 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9044 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9045
9046 /* Set speaker pin to front mixer */
9047 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9048
9049 /* Init headphone pin */
9050 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9051 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9052 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9053 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9054
9055 { } /* end */
9056};
9057
9058/* toggle speaker-output according to the hp-jack state */
9059static void alc883_medion_wim2160_setup(struct hda_codec *codec)
9060{
9061 struct alc_spec *spec = codec->spec;
9062
9063 spec->autocfg.hp_pins[0] = 0x1a;
9064 spec->autocfg.speaker_pins[0] = 0x15;
9065}
9066
Tobin Davis2880a862007-08-07 11:50:26 +02009067static struct snd_kcontrol_new alc883_acer_aspire_mixer[] = {
Kailang Yangd1a991a2007-08-15 16:21:59 +02009068 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9069 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009070 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009071 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9072 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009073 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009074 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangd1a991a2007-08-15 16:21:59 +02009075 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Tobin Davis2880a862007-08-07 11:50:26 +02009076 { } /* end */
Kailang Yangd1a991a2007-08-15 16:21:59 +02009077};
Tobin Davis2880a862007-08-07 11:50:26 +02009078
Tony Vroond2fd4b02009-06-21 00:40:10 +01009079static struct snd_kcontrol_new alc888_acer_aspire_6530_mixer[] = {
9080 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009081 HDA_CODEC_VOLUME("LFE Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
Tony Vroon684a8842009-06-26 09:27:50 +01009082 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9083 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009084 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9085 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9086 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009087 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroond2fd4b02009-06-21 00:40:10 +01009088 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9089 { } /* end */
9090};
9091
Kailang Yange2757d52008-08-26 13:17:46 +02009092static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = {
9093 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9094 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9095 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
9096 HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
9097 HDA_CODEC_VOLUME_MONO("Center Playback Volume",
9098 0x0d, 1, 0x0, HDA_OUTPUT),
9099 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
9100 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
9101 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
9102 HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
9103 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009104 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
9105 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
9106 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9107 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9108 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009109 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009110 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
9111 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009112 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009113 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009114 { } /* end */
9115};
9116
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009117static struct snd_kcontrol_new alc889A_mb31_mixer[] = {
9118 /* Output mixers */
9119 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
9120 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT),
9121 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT),
9122 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT),
9123 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00,
9124 HDA_OUTPUT),
9125 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT),
9126 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT),
9127 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT),
9128 /* Output switches */
9129 HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT),
9130 HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT),
9131 HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT),
9132 /* Boost mixers */
David Henningsson5f99f862011-01-04 15:24:24 +01009133 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x00, HDA_INPUT),
9134 HDA_CODEC_VOLUME("Line Boost Volume", 0x1a, 0x00, HDA_INPUT),
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009135 /* Input mixers */
9136 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT),
9137 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT),
9138 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9139 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9140 { } /* end */
9141};
9142
Guido Günther3e1647c2009-06-05 00:47:26 +02009143static struct snd_kcontrol_new alc883_vaiott_mixer[] = {
9144 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9145 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9146 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
9147 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009148 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
Guido Günther3e1647c2009-06-05 00:47:26 +02009149 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
9150 { } /* end */
9151};
9152
Kailang Yange2757d52008-08-26 13:17:46 +02009153static struct hda_bind_ctls alc883_bind_cap_vol = {
9154 .ops = &snd_hda_bind_vol,
9155 .values = {
9156 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9157 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9158 0
9159 },
9160};
9161
9162static struct hda_bind_ctls alc883_bind_cap_switch = {
9163 .ops = &snd_hda_bind_sw,
9164 .values = {
9165 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
9166 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
9167 0
9168 },
9169};
9170
9171static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = {
9172 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
9173 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
9174 HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
9175 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
9176 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
9177 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01009178 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yange2757d52008-08-26 13:17:46 +02009179 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Takashi Iwaif9e336f2008-10-31 16:37:07 +01009180 { } /* end */
9181};
9182
9183static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = {
Kailang Yange2757d52008-08-26 13:17:46 +02009184 HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol),
9185 HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch),
9186 {
9187 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9188 /* .name = "Capture Source", */
9189 .name = "Input Source",
9190 .count = 1,
Takashi Iwai54cbc9a2008-10-31 15:24:04 +01009191 .info = alc_mux_enum_info,
9192 .get = alc_mux_enum_get,
9193 .put = alc_mux_enum_put,
Kailang Yange2757d52008-08-26 13:17:46 +02009194 },
9195 { } /* end */
9196};
9197
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009198static struct snd_kcontrol_new alc883_chmode_mixer[] = {
9199 {
9200 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9201 .name = "Channel Mode",
9202 .info = alc_ch_mode_info,
9203 .get = alc_ch_mode_get,
9204 .put = alc_ch_mode_put,
9205 },
9206 { } /* end */
9207};
9208
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009209/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009210static void alc883_mitac_setup(struct hda_codec *codec)
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009211{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009212 struct alc_spec *spec = codec->spec;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009213
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009214 spec->autocfg.hp_pins[0] = 0x15;
9215 spec->autocfg.speaker_pins[0] = 0x14;
9216 spec->autocfg.speaker_pins[1] = 0x17;
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009217}
9218
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009219static struct hda_verb alc883_mitac_verbs[] = {
9220 /* HP */
9221 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9222 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9223 /* Subwoofer */
9224 {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
9225 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9226
9227 /* enable unsolicited event */
9228 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9229 /* {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, */
9230
9231 { } /* end */
9232};
9233
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309234static struct hda_verb alc883_clevo_m540r_verbs[] = {
9235 /* HP */
9236 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9237 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9238 /* Int speaker */
9239 /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/
9240
9241 /* enable unsolicited event */
9242 /*
9243 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9244 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9245 */
9246
9247 { } /* end */
9248};
9249
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009250static struct hda_verb alc883_clevo_m720_verbs[] = {
Jiang zhe368c7a92008-03-04 11:20:33 +01009251 /* HP */
9252 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9253 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9254 /* Int speaker */
9255 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
9256 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9257
9258 /* enable unsolicited event */
9259 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009260 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Jiang zhe368c7a92008-03-04 11:20:33 +01009261
9262 { } /* end */
9263};
9264
Jiang zhefb97dc62008-03-06 11:07:11 +01009265static struct hda_verb alc883_2ch_fujitsu_pi2515_verbs[] = {
9266 /* HP */
9267 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9268 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9269 /* Subwoofer */
9270 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
9271 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9272
9273 /* enable unsolicited event */
9274 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9275
9276 { } /* end */
9277};
9278
Sasha Alexandrc2592492009-06-16 14:52:54 -04009279static struct hda_verb alc883_targa_verbs[] = {
Kailang Yangccc656c2006-10-17 12:32:26 +02009280 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9281 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9282
9283 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9284 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangea1fb292008-08-26 12:58:38 +02009285
David Heidelberger64a8be72009-06-08 16:15:18 +02009286/* Connect Line-Out side jack (SPDIF) to Side */
9287 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9288 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9289 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
9290/* Connect Mic jack to CLFE */
9291 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9292 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9293 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02},
9294/* Connect Line-in jack to Surround */
9295 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9296 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9297 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
9298/* Connect HP out jack to Front */
9299 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9300 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9301 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangccc656c2006-10-17 12:32:26 +02009302
9303 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangccc656c2006-10-17 12:32:26 +02009304
9305 { } /* end */
9306};
9307
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009308static struct hda_verb alc883_lenovo_101e_verbs[] = {
9309 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9310 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT|AC_USRSP_EN},
9311 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT|AC_USRSP_EN},
9312 { } /* end */
9313};
9314
Kailang Yang272a5272007-05-14 11:00:38 +02009315static struct hda_verb alc883_lenovo_nb0763_verbs[] = {
9316 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9317 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9318 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9319 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9320 { } /* end */
9321};
9322
9323static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
9324 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9325 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9326 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9327 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_FRONT_EVENT | AC_USRSP_EN},
9328 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9329 { } /* end */
9330};
9331
Kailang Yang189609a2007-08-20 11:31:23 +02009332static struct hda_verb alc883_haier_w66_verbs[] = {
9333 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9334 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9335
9336 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9337
9338 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
9339 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9340 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9341 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9342 { } /* end */
9343};
9344
Kailang Yange2757d52008-08-26 13:17:46 +02009345static struct hda_verb alc888_lenovo_sky_verbs[] = {
9346 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9347 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9348 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9349 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9350 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9351 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9352 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
9353 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9354 { } /* end */
9355};
9356
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009357static struct hda_verb alc888_6st_dell_verbs[] = {
9358 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9359 { }
9360};
9361
Guido Günther3e1647c2009-06-05 00:47:26 +02009362static struct hda_verb alc883_vaiott_verbs[] = {
9363 /* HP */
9364 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
9365 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9366
9367 /* enable unsolicited event */
9368 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9369
9370 { } /* end */
9371};
9372
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009373static void alc888_3st_hp_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009374{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009375 struct alc_spec *spec = codec->spec;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009376
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009377 spec->autocfg.hp_pins[0] = 0x1b;
9378 spec->autocfg.speaker_pins[0] = 0x14;
9379 spec->autocfg.speaker_pins[1] = 0x16;
9380 spec->autocfg.speaker_pins[2] = 0x18;
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009381}
9382
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009383static struct hda_verb alc888_3st_hp_verbs[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009384 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
Herton Ronaldo Krzesinskif32a19e2008-03-18 09:27:08 +01009385 {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
9386 {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009387 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Herton Ronaldo Krzesinski8718b702009-03-04 14:22:51 -03009388 { } /* end */
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009389};
9390
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009391/*
9392 * 2ch mode
9393 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009394static struct hda_verb alc888_3st_hp_2ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009395 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9396 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9397 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
9398 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009399 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009400};
9401
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009402/*
9403 * 4ch mode
9404 */
9405static struct hda_verb alc888_3st_hp_4ch_init[] = {
9406 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
9407 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
9408 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9409 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
9410 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9411 { } /* end */
9412};
9413
9414/*
9415 * 6ch mode
9416 */
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009417static struct hda_verb alc888_3st_hp_6ch_init[] = {
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009418 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9419 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009420 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009421 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
9422 { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009423 { 0x16, AC_VERB_SET_CONNECT_SEL, 0x01 },
9424 { } /* end */
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009425};
9426
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009427static struct hda_channel_mode alc888_3st_hp_modes[3] = {
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009428 { 2, alc888_3st_hp_2ch_init },
Herton Ronaldo Krzesinski3ea0d7c2009-03-04 14:22:50 -03009429 { 4, alc888_3st_hp_4ch_init },
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009430 { 6, alc888_3st_hp_6ch_init },
Claudio Matsuoka8341de62007-07-06 12:10:45 +02009431};
9432
Kailang Yang272a5272007-05-14 11:00:38 +02009433/* toggle front-jack and RCA according to the hp-jack state */
9434static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
9435{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009436 unsigned int present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangea1fb292008-08-26 12:58:38 +02009437
Takashi Iwai47fd8302007-08-10 17:11:07 +02009438 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9439 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9440 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9441 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009442}
9443
9444/* toggle RCA according to the front-jack state */
9445static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec)
9446{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009447 unsigned int present = snd_hda_jack_detect(codec, 0x14);
Kailang Yangea1fb292008-08-26 12:58:38 +02009448
Takashi Iwai47fd8302007-08-10 17:11:07 +02009449 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9450 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Kailang Yang272a5272007-05-14 11:00:38 +02009451}
Takashi Iwai47fd8302007-08-10 17:11:07 +02009452
Kailang Yang272a5272007-05-14 11:00:38 +02009453static void alc883_lenovo_ms7195_unsol_event(struct hda_codec *codec,
9454 unsigned int res)
9455{
9456 if ((res >> 26) == ALC880_HP_EVENT)
9457 alc888_lenovo_ms7195_front_automute(codec);
9458 if ((res >> 26) == ALC880_FRONT_EVENT)
9459 alc888_lenovo_ms7195_rca_automute(codec);
9460}
9461
Kailang Yang272a5272007-05-14 11:00:38 +02009462/* toggle speaker-output according to the hp-jack state */
Takashi Iwaidc427172010-11-29 07:42:59 +01009463static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +02009464{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009465 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009466
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009467 spec->autocfg.hp_pins[0] = 0x14;
9468 spec->autocfg.speaker_pins[0] = 0x15;
Kailang Yang272a5272007-05-14 11:00:38 +02009469}
9470
Kailang Yangccc656c2006-10-17 12:32:26 +02009471/* toggle speaker-output according to the hp-jack state */
Sasha Alexandrc2592492009-06-16 14:52:54 -04009472#define alc883_targa_init_hook alc882_targa_init_hook
9473#define alc883_targa_unsol_event alc882_targa_unsol_event
Jiang zhe368c7a92008-03-04 11:20:33 +01009474
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009475static void alc883_clevo_m720_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009476{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009477 struct alc_spec *spec = codec->spec;
9478
9479 spec->autocfg.hp_pins[0] = 0x15;
9480 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009481}
9482
9483static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
9484{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009485 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +01009486 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009487}
9488
9489static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
Jiang zhe368c7a92008-03-04 11:20:33 +01009490 unsigned int res)
9491{
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009492 switch (res >> 26) {
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009493 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +01009494 alc88x_simple_mic_automute(codec);
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009495 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009496 default:
9497 alc_automute_amp_unsol_event(codec, res);
9498 break;
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009499 }
Jiang zhe368c7a92008-03-04 11:20:33 +01009500}
9501
Jiang zhefb97dc62008-03-06 11:07:11 +01009502/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009503static void alc883_2ch_fujitsu_pi2515_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009504{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009505 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009506
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009507 spec->autocfg.hp_pins[0] = 0x14;
9508 spec->autocfg.speaker_pins[0] = 0x15;
Jiang zhefb97dc62008-03-06 11:07:11 +01009509}
9510
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009511static void alc883_haier_w66_setup(struct hda_codec *codec)
Jiang zhefb97dc62008-03-06 11:07:11 +01009512{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009513 struct alc_spec *spec = codec->spec;
Jiang zhefb97dc62008-03-06 11:07:11 +01009514
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009515 spec->autocfg.hp_pins[0] = 0x1b;
9516 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang189609a2007-08-20 11:31:23 +02009517}
9518
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009519static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
9520{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009521 int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009522
Takashi Iwai47fd8302007-08-10 17:11:07 +02009523 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9524 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009525}
9526
9527static void alc883_lenovo_101e_all_automute(struct hda_codec *codec)
9528{
Wu Fengguang864f92b2009-11-18 12:38:02 +08009529 int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0;
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009530
Takashi Iwai47fd8302007-08-10 17:11:07 +02009531 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
9532 HDA_AMP_MUTE, bits);
9533 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9534 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009535}
9536
9537static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec,
9538 unsigned int res)
9539{
9540 if ((res >> 26) == ALC880_HP_EVENT)
9541 alc883_lenovo_101e_all_automute(codec);
9542 if ((res >> 26) == ALC880_FRONT_EVENT)
9543 alc883_lenovo_101e_ispeaker_automute(codec);
9544}
9545
Takashi Iwai676a9b52007-08-16 15:23:35 +02009546/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009547static void alc883_acer_aspire_setup(struct hda_codec *codec)
Takashi Iwai676a9b52007-08-16 15:23:35 +02009548{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009549 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009550
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009551 spec->autocfg.hp_pins[0] = 0x14;
9552 spec->autocfg.speaker_pins[0] = 0x15;
9553 spec->autocfg.speaker_pins[1] = 0x16;
Takashi Iwai676a9b52007-08-16 15:23:35 +02009554}
9555
Kailang Yangd1a991a2007-08-15 16:21:59 +02009556static struct hda_verb alc883_acer_eapd_verbs[] = {
9557 /* HP Pin: output 0 (0x0c) */
9558 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9559 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
9560 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
9561 /* Front Pin: output 0 (0x0c) */
Takashi Iwai676a9b52007-08-16 15:23:35 +02009562 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9563 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009564 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009565 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
9566 /* eanable EAPD on medion laptop */
9567 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
9568 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
Takashi Iwai676a9b52007-08-16 15:23:35 +02009569 /* enable unsolicited event */
9570 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Kailang Yangd1a991a2007-08-15 16:21:59 +02009571 { }
9572};
9573
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009574static void alc888_6st_dell_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009575{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009576 struct alc_spec *spec = codec->spec;
Kailang Yangea1fb292008-08-26 12:58:38 +02009577
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009578 spec->autocfg.hp_pins[0] = 0x1b;
9579 spec->autocfg.speaker_pins[0] = 0x14;
9580 spec->autocfg.speaker_pins[1] = 0x15;
9581 spec->autocfg.speaker_pins[2] = 0x16;
9582 spec->autocfg.speaker_pins[3] = 0x17;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009583}
9584
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009585static void alc888_lenovo_sky_setup(struct hda_codec *codec)
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009586{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009587 struct alc_spec *spec = codec->spec;
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009588
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009589 spec->autocfg.hp_pins[0] = 0x1b;
9590 spec->autocfg.speaker_pins[0] = 0x14;
9591 spec->autocfg.speaker_pins[1] = 0x15;
9592 spec->autocfg.speaker_pins[2] = 0x16;
9593 spec->autocfg.speaker_pins[3] = 0x17;
9594 spec->autocfg.speaker_pins[4] = 0x1a;
Kailang Yange2757d52008-08-26 13:17:46 +02009595}
9596
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009597static void alc883_vaiott_setup(struct hda_codec *codec)
Guido Günther3e1647c2009-06-05 00:47:26 +02009598{
9599 struct alc_spec *spec = codec->spec;
9600
9601 spec->autocfg.hp_pins[0] = 0x15;
9602 spec->autocfg.speaker_pins[0] = 0x14;
9603 spec->autocfg.speaker_pins[1] = 0x17;
Guido Günther3e1647c2009-06-05 00:47:26 +02009604}
9605
Kailang Yange2757d52008-08-26 13:17:46 +02009606static struct hda_verb alc888_asus_m90v_verbs[] = {
9607 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9608 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9609 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
9610 /* enable unsolicited event */
9611 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9612 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
9613 { } /* end */
9614};
9615
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009616static void alc883_mode2_setup(struct hda_codec *codec)
Kailang Yange2757d52008-08-26 13:17:46 +02009617{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009618 struct alc_spec *spec = codec->spec;
Kailang Yange2757d52008-08-26 13:17:46 +02009619
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009620 spec->autocfg.hp_pins[0] = 0x1b;
9621 spec->autocfg.speaker_pins[0] = 0x14;
9622 spec->autocfg.speaker_pins[1] = 0x15;
9623 spec->autocfg.speaker_pins[2] = 0x16;
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009624 spec->ext_mic.pin = 0x18;
9625 spec->int_mic.pin = 0x19;
9626 spec->ext_mic.mux_idx = 0;
9627 spec->int_mic.mux_idx = 1;
9628 spec->auto_mic = 1;
Kailang Yange2757d52008-08-26 13:17:46 +02009629}
9630
9631static struct hda_verb alc888_asus_eee1601_verbs[] = {
9632 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
9633 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
9634 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
9635 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
9636 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
9637 {0x20, AC_VERB_SET_COEF_INDEX, 0x0b},
9638 {0x20, AC_VERB_SET_PROC_COEF, 0x0838},
9639 /* enable unsolicited event */
9640 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9641 { } /* end */
9642};
9643
Kailang Yange2757d52008-08-26 13:17:46 +02009644static void alc883_eee1601_inithook(struct hda_codec *codec)
9645{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +02009646 struct alc_spec *spec = codec->spec;
9647
9648 spec->autocfg.hp_pins[0] = 0x14;
9649 spec->autocfg.speaker_pins[0] = 0x1b;
9650 alc_automute_pin(codec);
Kailang Yange2757d52008-08-26 13:17:46 +02009651}
9652
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009653static struct hda_verb alc889A_mb31_verbs[] = {
9654 /* Init rear pin (used as headphone output) */
9655 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */
9656 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */
9657 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
9658 /* Init line pin (used as output in 4ch and 6ch mode) */
9659 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */
9660 /* Init line 2 pin (used as headphone out by default) */
9661 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */
9662 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */
9663 { } /* end */
9664};
9665
9666/* Mute speakers according to the headphone jack state */
9667static void alc889A_mb31_automute(struct hda_codec *codec)
9668{
9669 unsigned int present;
9670
9671 /* Mute only in 2ch or 4ch mode */
9672 if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0)
9673 == 0x00) {
Wu Fengguang864f92b2009-11-18 12:38:02 +08009674 present = snd_hda_jack_detect(codec, 0x15);
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009675 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
9676 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9677 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
9678 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
9679 }
9680}
9681
9682static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res)
9683{
9684 if ((res >> 26) == ALC880_HP_EVENT)
9685 alc889A_mb31_automute(codec);
9686}
9687
Takashi Iwai49535502009-06-30 15:28:30 +02009688
Takashi Iwaicb53c622007-08-10 17:21:45 +02009689#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwai49535502009-06-30 15:28:30 +02009690#define alc882_loopbacks alc880_loopbacks
Takashi Iwaicb53c622007-08-10 17:21:45 +02009691#endif
9692
Sasha Alexandrdef319f2009-06-16 16:00:15 -04009693/* pcm configuration: identical with ALC880 */
Takashi Iwai49535502009-06-30 15:28:30 +02009694#define alc882_pcm_analog_playback alc880_pcm_analog_playback
9695#define alc882_pcm_analog_capture alc880_pcm_analog_capture
9696#define alc882_pcm_digital_playback alc880_pcm_digital_playback
9697#define alc882_pcm_digital_capture alc880_pcm_digital_capture
9698
9699static hda_nid_t alc883_slave_dig_outs[] = {
9700 ALC1200_DIGOUT_NID, 0,
9701};
9702
9703static hda_nid_t alc1200_slave_dig_outs[] = {
9704 ALC883_DIGOUT_NID, 0,
9705};
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009706
9707/*
9708 * configuration and preset
9709 */
Takashi Iwai49535502009-06-30 15:28:30 +02009710static const char *alc882_models[ALC882_MODEL_LAST] = {
9711 [ALC882_3ST_DIG] = "3stack-dig",
9712 [ALC882_6ST_DIG] = "6stack-dig",
9713 [ALC882_ARIMA] = "arima",
9714 [ALC882_W2JC] = "w2jc",
9715 [ALC882_TARGA] = "targa",
9716 [ALC882_ASUS_A7J] = "asus-a7j",
9717 [ALC882_ASUS_A7M] = "asus-a7m",
9718 [ALC885_MACPRO] = "macpro",
9719 [ALC885_MB5] = "mb5",
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009720 [ALC885_MACMINI3] = "macmini3",
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009721 [ALC885_MBA21] = "mba21",
Takashi Iwai49535502009-06-30 15:28:30 +02009722 [ALC885_MBP3] = "mbp3",
9723 [ALC885_IMAC24] = "imac24",
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009724 [ALC885_IMAC91] = "imac91",
Takashi Iwai49535502009-06-30 15:28:30 +02009725 [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009726 [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig",
9727 [ALC883_3ST_6ch] = "3stack-6ch",
Takashi Iwai49535502009-06-30 15:28:30 +02009728 [ALC883_6ST_DIG] = "alc883-6stack-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009729 [ALC883_TARGA_DIG] = "targa-dig",
9730 [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig",
David Heidelberger64a8be72009-06-08 16:15:18 +02009731 [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009732 [ALC883_ACER] = "acer",
Tobin Davis2880a862007-08-07 11:50:26 +02009733 [ALC883_ACER_ASPIRE] = "acer-aspire",
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009734 [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g",
Takashi Iwaib1a91462009-06-21 10:56:44 +02009735 [ALC888_ACER_ASPIRE_6530G] = "acer-aspire-6530g",
Hector Martin3b315d72009-06-02 10:54:19 +02009736 [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009737 [ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009738 [ALC883_MEDION] = "medion",
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +02009739 [ALC883_MEDION_WIM2160] = "medion-wim2160",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009740 [ALC883_LAPTOP_EAPD] = "laptop-eapd",
Kailang Yangbc9f98a2007-04-12 13:06:07 +02009741 [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
Kailang Yang272a5272007-05-14 11:00:38 +02009742 [ALC883_LENOVO_NB0763] = "lenovo-nb0763",
9743 [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
Kailang Yange2757d52008-08-26 13:17:46 +02009744 [ALC888_LENOVO_SKY] = "lenovo-sky",
Kailang Yang189609a2007-08-20 11:31:23 +02009745 [ALC883_HAIER_W66] = "haier-w66",
Claudio Matsuoka4723c022007-07-13 14:36:19 +02009746 [ALC888_3ST_HP] = "3stack-hp",
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009747 [ALC888_6ST_DELL] = "6stack-dell",
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +01009748 [ALC883_MITAC] = "mitac",
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309749 [ALC883_CLEVO_M540R] = "clevo-m540r",
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009750 [ALC883_CLEVO_M720] = "clevo-m720",
Jiang zhefb97dc62008-03-06 11:07:11 +01009751 [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009752 [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530",
Jiang zhe17bba1b2008-06-04 12:11:07 +02009753 [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel",
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009754 [ALC889A_INTEL] = "intel-alc889a",
9755 [ALC889_INTEL] = "intel-x58",
Wu Fengguang3ab90932008-11-17 09:51:09 +01009756 [ALC1200_ASUS_P5Q] = "asus-p5q",
Torben Schulzeb4c41d2009-05-18 15:02:35 +02009757 [ALC889A_MB31] = "mb31",
Guido Günther3e1647c2009-06-05 00:47:26 +02009758 [ALC883_SONY_VAIO_TT] = "sony-vaio-tt",
Takashi Iwai49535502009-06-30 15:28:30 +02009759 [ALC882_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009760};
9761
Takashi Iwai49535502009-06-30 15:28:30 +02009762static struct snd_pci_quirk alc882_cfg_tbl[] = {
9763 SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG),
9764
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009765 SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE),
Takashi Iwai69e50282008-11-03 10:07:43 +01009766 SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE),
Takashi Iwai9b6682f2009-03-23 22:50:52 +01009767 SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009768 SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_ACER_ASPIRE),
9769 SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_ACER_ASPIRE),
Jaroslav Kysela0b18cb12008-07-28 17:07:07 +02009770 SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_ACER_ASPIRE),
Vincent Petry5b2d1ec2008-11-18 22:21:57 +08009771 SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
9772 ALC888_ACER_ASPIRE_4930G),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009773 SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
Takashi Iwai83dd7402009-11-24 08:57:53 +01009774 ALC888_ACER_ASPIRE_4930G),
Hector Martin3b315d72009-06-02 10:54:19 +02009775 SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
9776 ALC888_ACER_ASPIRE_8930G),
Takashi Iwaie46b0c82009-06-13 10:16:43 +02009777 SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
9778 ALC888_ACER_ASPIRE_8930G),
Takashi Iwai49535502009-06-30 15:28:30 +02009779 SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO),
9780 SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO),
Lukasz Wojnilowicza8e4f9d2009-01-08 12:00:49 +01009781 SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
Takashi Iwaidde65352009-06-25 08:25:35 +02009782 ALC888_ACER_ASPIRE_6530G),
Juan Jesus Garcia de Soriacc374c42009-02-23 08:11:59 +01009783 SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
Tony Vroond2fd4b02009-06-21 00:40:10 +01009784 ALC888_ACER_ASPIRE_6530G),
Denis Kuplyakovfc86f952009-08-25 18:15:59 +02009785 SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
9786 ALC888_ACER_ASPIRE_7730G),
Takashi Iwai22b530e2009-05-13 11:32:52 +02009787 /* default Acer -- disabled as it causes more problems.
9788 * model=auto should work fine now
9789 */
9790 /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */
Takashi Iwai49535502009-06-30 15:28:30 +02009791
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +01009792 SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
Takashi Iwai49535502009-06-30 15:28:30 +02009793
Tobin Davisfebe3372007-06-12 11:27:46 +02009794 SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009795 SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
9796 SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
Herton Ronaldo Krzesinski5d85f8d2008-03-20 12:13:46 +01009797 SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG),
Chris Bagwell06bf3e12009-01-01 10:32:08 +01009798 SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP),
Herton Ronaldo Krzesinski7ec30f02009-03-04 14:22:52 -03009799 SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP),
Takashi Iwai49535502009-06-30 15:28:30 +02009800
9801 SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
9802 SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J),
9803 SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M),
Kailang Yanga01c30c2008-10-15 11:14:58 +02009804 SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V),
Takashi Iwai49535502009-06-30 15:28:30 +02009805 SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
9806 SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
9807 SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009808 SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG),
Mackenzie Morgan44a678d2009-02-10 17:13:43 +01009809 SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG),
Wu Fengguang3ab90932008-11-17 09:51:09 +01009810 SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q),
Kailang Yange2757d52008-08-26 13:17:46 +02009811 SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601),
Takashi Iwai49535502009-06-30 15:28:30 +02009812
9813 SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT),
Travis Place97ec7102008-05-23 18:31:46 +02009814 SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009815 SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009816 SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009817 SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC),
9818 SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD),
Kailang Yange2757d52008-08-26 13:17:46 +02009819 SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009820 SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009821 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG),
9822
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009823 SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
9824 SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG),
9825 SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009826 SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
Takashi Iwai2fef62c2009-12-18 08:48:42 +01009827 SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO),
Takashi Iwai49535502009-06-30 15:28:30 +02009828 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009829 SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
Pascal Terjan82808232008-03-04 11:33:28 +01009830 SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009831 SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG),
9832 SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
9833 SND_PCI_QUIRK(0x1462, 0x3fc1, "MSI", ALC883_TARGA_DIG),
9834 SND_PCI_QUIRK(0x1462, 0x3fc3, "MSI", ALC883_TARGA_DIG),
9835 SND_PCI_QUIRK(0x1462, 0x3fcc, "MSI", ALC883_TARGA_DIG),
9836 SND_PCI_QUIRK(0x1462, 0x3fdf, "MSI", ALC883_TARGA_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009837 SND_PCI_QUIRK(0x1462, 0x42cd, "MSI", ALC883_TARGA_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009838 SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG),
9839 SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG),
9840 SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009841 SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG),
David Heidelberger64a8be72009-06-08 16:15:18 +02009842 SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009843 SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG),
9844 SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
Tobin Davis799f88a2007-05-29 14:29:08 +02009845 SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
Takashi Iwaiee095432008-11-25 15:03:38 +01009846 SND_PCI_QUIRK(0x1462, 0x7260, "MSI 7260", ALC883_TARGA_DIG),
Herton Ronaldo Krzesinski86d34b72008-03-18 09:27:59 +01009847 SND_PCI_QUIRK(0x1462, 0x7267, "MSI", ALC883_3ST_6ch_DIG),
Leonard Norrgard2a296cb2007-01-08 11:28:22 +01009848 SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
Tobin Davis2dcd5222007-07-10 17:04:57 +02009849 SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
Sasha Alexandrdf01b8a2009-06-16 14:46:17 -04009850 SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG),
Anisse Astierb43f6e52010-03-10 19:17:46 +01009851 SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009852 SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG),
William Westonb1e44222009-07-08 01:10:05 -07009853 SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009854
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009855 SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG),
Joerg Schirottked1501ea2010-04-15 08:37:41 +02009856 SND_PCI_QUIRK(0x1558, 0x0571, "Clevo laptop M570U", ALC883_3ST_6ch_DIG),
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +01009857 SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720),
9858 SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720),
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -04309859 SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R),
Takashi Iwaidea0a502009-02-09 17:14:52 +01009860 SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
Daniel T Chene60623b2007-05-29 03:41:55 -04009861 SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
Takashi Iwai49535502009-06-30 15:28:30 +02009862 /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01009863 SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009864 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
Takashi Iwaif67d8172009-02-04 23:30:19 +01009865 ALC883_FUJITSU_PI2515),
Takashi Iwaibfb53032009-04-14 14:51:04 +02009866 SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
Vincent Petryef8ef5f2008-11-23 11:31:41 +08009867 ALC888_FUJITSU_XA3530),
Kailang Yang272a5272007-05-14 11:00:38 +02009868 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
Kailang Yang272a5272007-05-14 11:00:38 +02009869 SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01009870 SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
9871 SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
Kailang Yange2757d52008-08-26 13:17:46 +02009872 SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
Takashi Iwai959973b2008-11-05 11:30:56 +01009873 SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
Andrew Paprocki0b167bf2008-02-03 10:15:44 +01009874 SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
Kailang Yang189609a2007-08-20 11:31:23 +02009875 SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
Takashi Iwai49535502009-06-30 15:28:30 +02009876
Jiang zhe17bba1b2008-06-04 12:11:07 +02009877 SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL),
9878 SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL),
Luke Yelavich2de686d2009-01-16 15:08:02 +11009879 SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC),
Jaroslav Kysela87a8c372009-07-23 10:58:29 +02009880 SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL),
9881 SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL),
9882 SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL),
Daniel T Chen572c0e32010-03-14 23:44:03 -04009883 SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG),
Takashi Iwai49535502009-06-30 15:28:30 +02009884
Takashi Iwai9c7f8522006-06-28 15:08:22 +02009885 {}
9886};
9887
Takashi Iwai49535502009-06-30 15:28:30 +02009888/* codec SSID table for Intel Mac */
9889static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
9890 SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3),
9891 SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3),
9892 SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3),
9893 SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO),
9894 SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
9895 SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
9896 SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
Daniel T Chen26fd74f2010-05-30 09:55:23 -04009897 SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
Justin P. Mattockab669962010-06-06 16:09:53 -07009898 SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_ASUS_A7M),
Justin P. Mattockf53dae22010-06-06 16:09:51 -07009899 SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC885_MBP3),
Justin P. Mattock6e129702010-06-06 16:09:49 -07009900 SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC885_MBA21),
Takashi Iwai49535502009-06-30 15:28:30 +02009901 SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
9902 SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
9903 SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
Justin P. Mattock4b7e1802009-12-07 15:07:46 -08009904 SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91),
Takashi Iwai49535502009-06-30 15:28:30 +02009905 SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5),
Luke Yelavich3bfea982010-06-22 11:04:19 +10009906 SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009907 /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2,
9908 * so apparently no perfect solution yet
Takashi Iwai49535502009-06-30 15:28:30 +02009909 */
9910 SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5),
Daniel T Chen46ef6ec2009-11-11 14:32:10 -05009911 SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5),
Luke Yelaviche458b1f2010-02-12 16:28:29 +11009912 SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC885_MACMINI3),
Takashi Iwai49535502009-06-30 15:28:30 +02009913 {} /* terminator */
Wu Fengguangf3cd3f52009-04-02 19:44:18 +08009914};
9915
Takashi Iwai49535502009-06-30 15:28:30 +02009916static struct alc_config_preset alc882_presets[] = {
9917 [ALC882_3ST_DIG] = {
9918 .mixers = { alc882_base_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009919 .init_verbs = { alc882_base_init_verbs,
9920 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009921 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9922 .dac_nids = alc882_dac_nids,
9923 .dig_out_nid = ALC882_DIGOUT_NID,
9924 .dig_in_nid = ALC882_DIGIN_NID,
9925 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
9926 .channel_mode = alc882_ch_modes,
9927 .need_dac_fix = 1,
9928 .input_mux = &alc882_capture_source,
9929 },
9930 [ALC882_6ST_DIG] = {
9931 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009932 .init_verbs = { alc882_base_init_verbs,
9933 alc882_adc1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009934 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9935 .dac_nids = alc882_dac_nids,
9936 .dig_out_nid = ALC882_DIGOUT_NID,
9937 .dig_in_nid = ALC882_DIGIN_NID,
9938 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9939 .channel_mode = alc882_sixstack_modes,
9940 .input_mux = &alc882_capture_source,
9941 },
9942 [ALC882_ARIMA] = {
9943 .mixers = { alc882_base_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009944 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9945 alc882_eapd_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009946 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9947 .dac_nids = alc882_dac_nids,
9948 .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes),
9949 .channel_mode = alc882_sixstack_modes,
9950 .input_mux = &alc882_capture_source,
9951 },
9952 [ALC882_W2JC] = {
9953 .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +02009954 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
9955 alc882_eapd_verbs, alc880_gpio1_init_verbs },
Takashi Iwai49535502009-06-30 15:28:30 +02009956 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9957 .dac_nids = alc882_dac_nids,
9958 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
9959 .channel_mode = alc880_threestack_modes,
9960 .need_dac_fix = 1,
9961 .input_mux = &alc882_capture_source,
9962 .dig_out_nid = ALC882_DIGOUT_NID,
9963 },
Reimundo Heluani76e6f5a2010-02-23 01:19:51 -08009964 [ALC885_MBA21] = {
9965 .mixers = { alc885_mba21_mixer },
9966 .init_verbs = { alc885_mba21_init_verbs, alc880_gpio1_init_verbs },
9967 .num_dacs = 2,
9968 .dac_nids = alc882_dac_nids,
9969 .channel_mode = alc885_mba21_ch_modes,
9970 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
9971 .input_mux = &alc882_capture_source,
9972 .unsol_event = alc_automute_amp_unsol_event,
9973 .setup = alc885_mba21_setup,
9974 .init_hook = alc_automute_amp,
9975 },
Takashi Iwai49535502009-06-30 15:28:30 +02009976 [ALC885_MBP3] = {
9977 .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer },
9978 .init_verbs = { alc885_mbp3_init_verbs,
9979 alc880_gpio1_init_verbs },
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009980 .num_dacs = 2,
Takashi Iwai49535502009-06-30 15:28:30 +02009981 .dac_nids = alc882_dac_nids,
Takashi Iwaibe0ae922009-08-31 08:27:10 +02009982 .hp_nid = 0x04,
9983 .channel_mode = alc885_mbp_4ch_modes,
9984 .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes),
Takashi Iwai49535502009-06-30 15:28:30 +02009985 .input_mux = &alc882_capture_source,
9986 .dig_out_nid = ALC882_DIGOUT_NID,
9987 .dig_in_nid = ALC882_DIGIN_NID,
9988 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +02009989 .setup = alc885_mbp3_setup,
9990 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +02009991 },
9992 [ALC885_MB5] = {
9993 .mixers = { alc885_mb5_mixer, alc882_chmode_mixer },
9994 .init_verbs = { alc885_mb5_init_verbs,
9995 alc880_gpio1_init_verbs },
9996 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
9997 .dac_nids = alc882_dac_nids,
9998 .channel_mode = alc885_mb5_6ch_modes,
9999 .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes),
10000 .input_mux = &mb5_capture_source,
10001 .dig_out_nid = ALC882_DIGOUT_NID,
10002 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010003 .unsol_event = alc_automute_amp_unsol_event,
10004 .setup = alc885_mb5_setup,
10005 .init_hook = alc_automute_amp,
Takashi Iwai49535502009-06-30 15:28:30 +020010006 },
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010007 [ALC885_MACMINI3] = {
10008 .mixers = { alc885_macmini3_mixer, alc882_chmode_mixer },
10009 .init_verbs = { alc885_macmini3_init_verbs,
10010 alc880_gpio1_init_verbs },
10011 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10012 .dac_nids = alc882_dac_nids,
10013 .channel_mode = alc885_macmini3_6ch_modes,
10014 .num_channel_mode = ARRAY_SIZE(alc885_macmini3_6ch_modes),
10015 .input_mux = &macmini3_capture_source,
10016 .dig_out_nid = ALC882_DIGOUT_NID,
10017 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010018 .unsol_event = alc_automute_amp_unsol_event,
10019 .setup = alc885_macmini3_setup,
10020 .init_hook = alc_automute_amp,
Luke Yelaviche458b1f2010-02-12 16:28:29 +110010021 },
Takashi Iwai49535502009-06-30 15:28:30 +020010022 [ALC885_MACPRO] = {
10023 .mixers = { alc882_macpro_mixer },
10024 .init_verbs = { alc882_macpro_init_verbs },
10025 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10026 .dac_nids = alc882_dac_nids,
10027 .dig_out_nid = ALC882_DIGOUT_NID,
10028 .dig_in_nid = ALC882_DIGIN_NID,
10029 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10030 .channel_mode = alc882_ch_modes,
10031 .input_mux = &alc882_capture_source,
10032 .init_hook = alc885_macpro_init_hook,
10033 },
10034 [ALC885_IMAC24] = {
10035 .mixers = { alc885_imac24_mixer },
10036 .init_verbs = { alc885_imac24_init_verbs },
10037 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10038 .dac_nids = alc882_dac_nids,
10039 .dig_out_nid = ALC882_DIGOUT_NID,
10040 .dig_in_nid = ALC882_DIGIN_NID,
10041 .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
10042 .channel_mode = alc882_ch_modes,
10043 .input_mux = &alc882_capture_source,
10044 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010045 .setup = alc885_imac24_setup,
Takashi Iwai49535502009-06-30 15:28:30 +020010046 .init_hook = alc885_imac24_init_hook,
10047 },
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010048 [ALC885_IMAC91] = {
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010049 .mixers = {alc885_imac91_mixer},
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010050 .init_verbs = { alc885_imac91_init_verbs,
10051 alc880_gpio1_init_verbs },
10052 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10053 .dac_nids = alc882_dac_nids,
Justin P. Mattockb7cccc52010-05-23 10:55:00 -070010054 .channel_mode = alc885_mba21_ch_modes,
10055 .num_channel_mode = ARRAY_SIZE(alc885_mba21_ch_modes),
10056 .input_mux = &alc889A_imac91_capture_source,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010057 .dig_out_nid = ALC882_DIGOUT_NID,
10058 .dig_in_nid = ALC882_DIGIN_NID,
Takashi Iwai9d54f082010-02-22 08:34:40 +010010059 .unsol_event = alc_automute_amp_unsol_event,
10060 .setup = alc885_imac91_setup,
10061 .init_hook = alc_automute_amp,
Justin P. Mattock4b7e1802009-12-07 15:07:46 -080010062 },
Takashi Iwai49535502009-06-30 15:28:30 +020010063 [ALC882_TARGA] = {
10064 .mixers = { alc882_targa_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010065 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
Takashi Iwai31909b82009-07-10 12:33:48 +020010066 alc880_gpio3_init_verbs, alc882_targa_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010067 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10068 .dac_nids = alc882_dac_nids,
10069 .dig_out_nid = ALC882_DIGOUT_NID,
10070 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10071 .adc_nids = alc882_adc_nids,
10072 .capsrc_nids = alc882_capsrc_nids,
10073 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10074 .channel_mode = alc882_3ST_6ch_modes,
10075 .need_dac_fix = 1,
10076 .input_mux = &alc882_capture_source,
10077 .unsol_event = alc882_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010078 .setup = alc882_targa_setup,
10079 .init_hook = alc882_targa_automute,
Takashi Iwai49535502009-06-30 15:28:30 +020010080 },
10081 [ALC882_ASUS_A7J] = {
10082 .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010083 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10084 alc882_asus_a7j_verbs},
Takashi Iwai49535502009-06-30 15:28:30 +020010085 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10086 .dac_nids = alc882_dac_nids,
10087 .dig_out_nid = ALC882_DIGOUT_NID,
10088 .num_adc_nids = ARRAY_SIZE(alc882_adc_nids),
10089 .adc_nids = alc882_adc_nids,
10090 .capsrc_nids = alc882_capsrc_nids,
10091 .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes),
10092 .channel_mode = alc882_3ST_6ch_modes,
10093 .need_dac_fix = 1,
10094 .input_mux = &alc882_capture_source,
10095 },
10096 [ALC882_ASUS_A7M] = {
10097 .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer },
Takashi Iwai8ab9e0a2009-07-03 10:58:12 +020010098 .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs,
10099 alc882_eapd_verbs, alc880_gpio1_init_verbs,
Takashi Iwai49535502009-06-30 15:28:30 +020010100 alc882_asus_a7m_verbs },
10101 .num_dacs = ARRAY_SIZE(alc882_dac_nids),
10102 .dac_nids = alc882_dac_nids,
10103 .dig_out_nid = ALC882_DIGOUT_NID,
10104 .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes),
10105 .channel_mode = alc880_threestack_modes,
10106 .need_dac_fix = 1,
10107 .input_mux = &alc882_capture_source,
10108 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010109 [ALC883_3ST_2ch_DIG] = {
10110 .mixers = { alc883_3ST_2ch_mixer },
10111 .init_verbs = { alc883_init_verbs },
10112 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10113 .dac_nids = alc883_dac_nids,
10114 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010115 .dig_in_nid = ALC883_DIGIN_NID,
10116 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10117 .channel_mode = alc883_3ST_2ch_modes,
10118 .input_mux = &alc883_capture_source,
10119 },
10120 [ALC883_3ST_6ch_DIG] = {
10121 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10122 .init_verbs = { alc883_init_verbs },
10123 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10124 .dac_nids = alc883_dac_nids,
10125 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010126 .dig_in_nid = ALC883_DIGIN_NID,
10127 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10128 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010129 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010130 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010131 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010132 [ALC883_3ST_6ch] = {
10133 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10134 .init_verbs = { alc883_init_verbs },
10135 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10136 .dac_nids = alc883_dac_nids,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010137 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10138 .channel_mode = alc883_3ST_6ch_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020010139 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010140 .input_mux = &alc883_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010141 },
Jiang zhe17bba1b2008-06-04 12:11:07 +020010142 [ALC883_3ST_6ch_INTEL] = {
10143 .mixers = { alc883_3ST_6ch_intel_mixer, alc883_chmode_mixer },
10144 .init_verbs = { alc883_init_verbs },
10145 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10146 .dac_nids = alc883_dac_nids,
10147 .dig_out_nid = ALC883_DIGOUT_NID,
10148 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangf3cd3f52009-04-02 19:44:18 +080010149 .slave_dig_outs = alc883_slave_dig_outs,
Jiang zhe17bba1b2008-06-04 12:11:07 +020010150 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_intel_modes),
10151 .channel_mode = alc883_3ST_6ch_intel_modes,
10152 .need_dac_fix = 1,
10153 .input_mux = &alc883_3stack_6ch_intel,
10154 },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010155 [ALC889A_INTEL] = {
10156 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020010157 .init_verbs = { alc885_init_verbs, alc885_init_input_verbs,
10158 alc_hp15_unsol_verbs },
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010159 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10160 .dac_nids = alc883_dac_nids,
10161 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10162 .adc_nids = alc889_adc_nids,
10163 .dig_out_nid = ALC883_DIGOUT_NID,
10164 .dig_in_nid = ALC883_DIGIN_NID,
10165 .slave_dig_outs = alc883_slave_dig_outs,
10166 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10167 .channel_mode = alc889_8ch_intel_modes,
10168 .capsrc_nids = alc889_capsrc_nids,
10169 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010170 .setup = alc889_automute_setup,
10171 .init_hook = alc_automute_amp,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010172 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010173 .need_dac_fix = 1,
10174 },
10175 [ALC889_INTEL] = {
10176 .mixers = { alc885_8ch_intel_mixer, alc883_chmode_mixer },
10177 .init_verbs = { alc885_init_verbs, alc889_init_input_verbs,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010178 alc889_eapd_verbs, alc_hp15_unsol_verbs},
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010179 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10180 .dac_nids = alc883_dac_nids,
10181 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10182 .adc_nids = alc889_adc_nids,
10183 .dig_out_nid = ALC883_DIGOUT_NID,
10184 .dig_in_nid = ALC883_DIGIN_NID,
10185 .slave_dig_outs = alc883_slave_dig_outs,
10186 .num_channel_mode = ARRAY_SIZE(alc889_8ch_intel_modes),
10187 .channel_mode = alc889_8ch_intel_modes,
10188 .capsrc_nids = alc889_capsrc_nids,
10189 .input_mux = &alc889_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010190 .setup = alc889_automute_setup,
Wu Fengguang6732bd02009-07-30 09:19:14 +020010191 .init_hook = alc889_intel_init_hook,
10192 .unsol_event = alc_automute_amp_unsol_event,
Jaroslav Kysela87a8c372009-07-23 10:58:29 +020010193 .need_dac_fix = 1,
10194 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010195 [ALC883_6ST_DIG] = {
10196 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10197 .init_verbs = { alc883_init_verbs },
10198 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10199 .dac_nids = alc883_dac_nids,
10200 .dig_out_nid = ALC883_DIGOUT_NID,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010201 .dig_in_nid = ALC883_DIGIN_NID,
10202 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10203 .channel_mode = alc883_sixstack_modes,
10204 .input_mux = &alc883_capture_source,
10205 },
Kailang Yangccc656c2006-10-17 12:32:26 +020010206 [ALC883_TARGA_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010207 .mixers = { alc883_targa_mixer, alc883_chmode_mixer },
David Heidelberger005b1072009-07-09 18:45:46 +020010208 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10209 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010210 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10211 .dac_nids = alc883_dac_nids,
10212 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010213 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10214 .channel_mode = alc883_3ST_6ch_modes,
10215 .need_dac_fix = 1,
10216 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010217 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010218 .setup = alc882_targa_setup,
10219 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010220 },
10221 [ALC883_TARGA_2ch_DIG] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010222 .mixers = { alc883_targa_2ch_mixer},
David Heidelberger005b1072009-07-09 18:45:46 +020010223 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
10224 alc883_targa_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020010225 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10226 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010227 .adc_nids = alc883_adc_nids_alt,
10228 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010229 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangccc656c2006-10-17 12:32:26 +020010230 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yangccc656c2006-10-17 12:32:26 +020010231 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10232 .channel_mode = alc883_3ST_2ch_modes,
10233 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010234 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010235 .setup = alc882_targa_setup,
10236 .init_hook = alc882_targa_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020010237 },
David Heidelberger64a8be72009-06-08 16:15:18 +020010238 [ALC883_TARGA_8ch_DIG] = {
Takashi Iwaib99dba32009-09-17 18:23:00 +020010239 .mixers = { alc883_targa_mixer, alc883_targa_8ch_mixer,
10240 alc883_chmode_mixer },
David Heidelberger64a8be72009-06-08 16:15:18 +020010241 .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010242 alc883_targa_verbs },
David Heidelberger64a8be72009-06-08 16:15:18 +020010243 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10244 .dac_nids = alc883_dac_nids,
10245 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10246 .adc_nids = alc883_adc_nids_rev,
10247 .capsrc_nids = alc883_capsrc_nids_rev,
10248 .dig_out_nid = ALC883_DIGOUT_NID,
10249 .dig_in_nid = ALC883_DIGIN_NID,
10250 .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes),
10251 .channel_mode = alc883_4ST_8ch_modes,
10252 .need_dac_fix = 1,
10253 .input_mux = &alc883_capture_source,
Sasha Alexandrc2592492009-06-16 14:52:54 -040010254 .unsol_event = alc883_targa_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010255 .setup = alc882_targa_setup,
10256 .init_hook = alc882_targa_automute,
David Heidelberger64a8be72009-06-08 16:15:18 +020010257 },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010258 [ALC883_ACER] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010259 .mixers = { alc883_base_mixer },
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010260 /* On TravelMate laptops, GPIO 0 enables the internal speaker
10261 * and the headphone jack. Turn this on and rely on the
10262 * standard mute methods whenever the user wants to turn
10263 * these outputs off.
10264 */
10265 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs },
10266 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10267 .dac_nids = alc883_dac_nids,
Vladimir Avdoninbab282b2006-08-22 13:31:58 +020010268 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10269 .channel_mode = alc883_3ST_2ch_modes,
10270 .input_mux = &alc883_capture_source,
10271 },
Tobin Davis2880a862007-08-07 11:50:26 +020010272 [ALC883_ACER_ASPIRE] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010273 .mixers = { alc883_acer_aspire_mixer },
Kailang Yangd1a991a2007-08-15 16:21:59 +020010274 .init_verbs = { alc883_init_verbs, alc883_acer_eapd_verbs },
Tobin Davis2880a862007-08-07 11:50:26 +020010275 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10276 .dac_nids = alc883_dac_nids,
10277 .dig_out_nid = ALC883_DIGOUT_NID,
Tobin Davis2880a862007-08-07 11:50:26 +020010278 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10279 .channel_mode = alc883_3ST_2ch_modes,
10280 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010281 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010282 .setup = alc883_acer_aspire_setup,
10283 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020010284 },
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010285 [ALC888_ACER_ASPIRE_4930G] = {
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010286 .mixers = { alc888_base_mixer,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010287 alc883_chmode_mixer },
10288 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10289 alc888_acer_aspire_4930g_verbs },
10290 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10291 .dac_nids = alc883_dac_nids,
10292 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10293 .adc_nids = alc883_adc_nids_rev,
10294 .capsrc_nids = alc883_capsrc_nids_rev,
10295 .dig_out_nid = ALC883_DIGOUT_NID,
10296 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10297 .channel_mode = alc883_3ST_6ch_modes,
10298 .need_dac_fix = 1,
Łukasz Wojniłowicz973b8cb2010-01-24 14:12:37 +010010299 .const_channel_count = 6,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010300 .num_mux_defs =
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010301 ARRAY_SIZE(alc888_2_capture_sources),
10302 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010303 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010304 .setup = alc888_acer_aspire_4930g_setup,
10305 .init_hook = alc_automute_amp,
Vincent Petry5b2d1ec2008-11-18 22:21:57 +080010306 },
Tony Vroond2fd4b02009-06-21 00:40:10 +010010307 [ALC888_ACER_ASPIRE_6530G] = {
10308 .mixers = { alc888_acer_aspire_6530_mixer },
10309 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10310 alc888_acer_aspire_6530g_verbs },
10311 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10312 .dac_nids = alc883_dac_nids,
10313 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10314 .adc_nids = alc883_adc_nids_rev,
10315 .capsrc_nids = alc883_capsrc_nids_rev,
10316 .dig_out_nid = ALC883_DIGOUT_NID,
10317 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10318 .channel_mode = alc883_3ST_2ch_modes,
10319 .num_mux_defs =
10320 ARRAY_SIZE(alc888_2_capture_sources),
10321 .input_mux = alc888_acer_aspire_6530_sources,
10322 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010323 .setup = alc888_acer_aspire_6530g_setup,
10324 .init_hook = alc_automute_amp,
Tony Vroond2fd4b02009-06-21 00:40:10 +010010325 },
Hector Martin3b315d72009-06-02 10:54:19 +020010326 [ALC888_ACER_ASPIRE_8930G] = {
Hector Martin556eea92009-12-20 22:51:23 +010010327 .mixers = { alc889_acer_aspire_8930g_mixer,
Hector Martin3b315d72009-06-02 10:54:19 +020010328 alc883_chmode_mixer },
10329 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
Hector Martin0f86a222009-12-20 22:51:18 +010010330 alc889_acer_aspire_8930g_verbs,
10331 alc889_eapd_verbs},
Hector Martin3b315d72009-06-02 10:54:19 +020010332 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10333 .dac_nids = alc883_dac_nids,
Hector Martin018df412009-06-04 00:13:40 +020010334 .num_adc_nids = ARRAY_SIZE(alc889_adc_nids),
10335 .adc_nids = alc889_adc_nids,
10336 .capsrc_nids = alc889_capsrc_nids,
Hector Martin3b315d72009-06-02 10:54:19 +020010337 .dig_out_nid = ALC883_DIGOUT_NID,
10338 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10339 .channel_mode = alc883_3ST_6ch_modes,
10340 .need_dac_fix = 1,
10341 .const_channel_count = 6,
10342 .num_mux_defs =
Hector Martin018df412009-06-04 00:13:40 +020010343 ARRAY_SIZE(alc889_capture_sources),
10344 .input_mux = alc889_capture_sources,
Hector Martin3b315d72009-06-02 10:54:19 +020010345 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010346 .setup = alc889_acer_aspire_8930g_setup,
10347 .init_hook = alc_automute_amp,
Hector Martinf5de24b2009-12-20 22:51:31 +010010348#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050010349 .power_hook = alc_power_eapd,
Hector Martinf5de24b2009-12-20 22:51:31 +010010350#endif
Hector Martin3b315d72009-06-02 10:54:19 +020010351 },
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010352 [ALC888_ACER_ASPIRE_7730G] = {
10353 .mixers = { alc883_3ST_6ch_mixer,
10354 alc883_chmode_mixer },
10355 .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs,
10356 alc888_acer_aspire_7730G_verbs },
10357 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10358 .dac_nids = alc883_dac_nids,
10359 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10360 .adc_nids = alc883_adc_nids_rev,
10361 .capsrc_nids = alc883_capsrc_nids_rev,
10362 .dig_out_nid = ALC883_DIGOUT_NID,
10363 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10364 .channel_mode = alc883_3ST_6ch_modes,
10365 .need_dac_fix = 1,
10366 .const_channel_count = 6,
10367 .input_mux = &alc883_capture_source,
10368 .unsol_event = alc_automute_amp_unsol_event,
Denis Kuplyakovd9477202010-11-24 06:01:09 +010010369 .setup = alc888_acer_aspire_7730g_setup,
Denis Kuplyakovfc86f952009-08-25 18:15:59 +020010370 .init_hook = alc_automute_amp,
10371 },
Tobin Davisc07584c2006-10-13 12:32:16 +020010372 [ALC883_MEDION] = {
10373 .mixers = { alc883_fivestack_mixer,
10374 alc883_chmode_mixer },
10375 .init_verbs = { alc883_init_verbs,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010376 alc883_medion_eapd_verbs },
Tobin Davisc07584c2006-10-13 12:32:16 +020010377 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10378 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010379 .adc_nids = alc883_adc_nids_alt,
10380 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010381 .capsrc_nids = alc883_capsrc_nids,
Tobin Davisc07584c2006-10-13 12:32:16 +020010382 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10383 .channel_mode = alc883_sixstack_modes,
10384 .input_mux = &alc883_capture_source,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010385 },
Maurus Cuelenaere7ad7b212010-04-06 18:12:52 +020010386 [ALC883_MEDION_WIM2160] = {
10387 .mixers = { alc883_medion_wim2160_mixer },
10388 .init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
10389 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10390 .dac_nids = alc883_dac_nids,
10391 .dig_out_nid = ALC883_DIGOUT_NID,
10392 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
10393 .adc_nids = alc883_adc_nids,
10394 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10395 .channel_mode = alc883_3ST_2ch_modes,
10396 .input_mux = &alc883_capture_source,
10397 .unsol_event = alc_automute_amp_unsol_event,
10398 .setup = alc883_medion_wim2160_setup,
10399 .init_hook = alc_automute_amp,
10400 },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010401 [ALC883_LAPTOP_EAPD] = {
Takashi Iwai676a9b52007-08-16 15:23:35 +020010402 .mixers = { alc883_base_mixer },
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010403 .init_verbs = { alc883_init_verbs, alc882_eapd_verbs },
10404 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10405 .dac_nids = alc883_dac_nids,
Andrew L. Neporadab373bde2006-11-07 11:37:08 +010010406 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10407 .channel_mode = alc883_3ST_2ch_modes,
10408 .input_mux = &alc883_capture_source,
10409 },
ddiaz@cenditel.gob.vea65cc602009-09-05 16:28:06 -043010410 [ALC883_CLEVO_M540R] = {
10411 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10412 .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs },
10413 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10414 .dac_nids = alc883_dac_nids,
10415 .dig_out_nid = ALC883_DIGOUT_NID,
10416 .dig_in_nid = ALC883_DIGIN_NID,
10417 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes),
10418 .channel_mode = alc883_3ST_6ch_clevo_modes,
10419 .need_dac_fix = 1,
10420 .input_mux = &alc883_capture_source,
10421 /* This machine has the hardware HP auto-muting, thus
10422 * we need no software mute via unsol event
10423 */
10424 },
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010425 [ALC883_CLEVO_M720] = {
10426 .mixers = { alc883_clevo_m720_mixer },
10427 .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs },
Jiang zhe368c7a92008-03-04 11:20:33 +010010428 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10429 .dac_nids = alc883_dac_nids,
10430 .dig_out_nid = ALC883_DIGOUT_NID,
10431 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10432 .channel_mode = alc883_3ST_2ch_modes,
10433 .input_mux = &alc883_capture_source,
Herton Ronaldo Krzesinski0c4cc442008-03-22 10:26:05 +010010434 .unsol_event = alc883_clevo_m720_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010435 .setup = alc883_clevo_m720_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010436 .init_hook = alc883_clevo_m720_init_hook,
Jiang zhe368c7a92008-03-04 11:20:33 +010010437 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010438 [ALC883_LENOVO_101E_2ch] = {
10439 .mixers = { alc883_lenovo_101e_2ch_mixer},
10440 .init_verbs = { alc883_init_verbs, alc883_lenovo_101e_verbs},
10441 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10442 .dac_nids = alc883_dac_nids,
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010443 .adc_nids = alc883_adc_nids_alt,
10444 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010445 .capsrc_nids = alc883_capsrc_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020010446 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10447 .channel_mode = alc883_3ST_2ch_modes,
10448 .input_mux = &alc883_lenovo_101e_capture_source,
10449 .unsol_event = alc883_lenovo_101e_unsol_event,
10450 .init_hook = alc883_lenovo_101e_all_automute,
10451 },
Kailang Yang272a5272007-05-14 11:00:38 +020010452 [ALC883_LENOVO_NB0763] = {
10453 .mixers = { alc883_lenovo_nb0763_mixer },
10454 .init_verbs = { alc883_init_verbs, alc883_lenovo_nb0763_verbs},
10455 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10456 .dac_nids = alc883_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020010457 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10458 .channel_mode = alc883_3ST_2ch_modes,
10459 .need_dac_fix = 1,
10460 .input_mux = &alc883_lenovo_nb0763_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010461 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwaidc427172010-11-29 07:42:59 +010010462 .setup = alc883_lenovo_nb0763_setup,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010463 .init_hook = alc_automute_amp,
Kailang Yang272a5272007-05-14 11:00:38 +020010464 },
10465 [ALC888_LENOVO_MS7195_DIG] = {
10466 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10467 .init_verbs = { alc883_init_verbs, alc888_lenovo_ms7195_verbs},
10468 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10469 .dac_nids = alc883_dac_nids,
10470 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang272a5272007-05-14 11:00:38 +020010471 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10472 .channel_mode = alc883_3ST_6ch_modes,
10473 .need_dac_fix = 1,
10474 .input_mux = &alc883_capture_source,
10475 .unsol_event = alc883_lenovo_ms7195_unsol_event,
10476 .init_hook = alc888_lenovo_ms7195_front_automute,
Kailang Yang189609a2007-08-20 11:31:23 +020010477 },
10478 [ALC883_HAIER_W66] = {
Sasha Alexandrc2592492009-06-16 14:52:54 -040010479 .mixers = { alc883_targa_2ch_mixer},
Kailang Yang189609a2007-08-20 11:31:23 +020010480 .init_verbs = { alc883_init_verbs, alc883_haier_w66_verbs},
10481 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10482 .dac_nids = alc883_dac_nids,
10483 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yang189609a2007-08-20 11:31:23 +020010484 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10485 .channel_mode = alc883_3ST_2ch_modes,
10486 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010487 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010488 .setup = alc883_haier_w66_setup,
10489 .init_hook = alc_automute_amp,
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010490 },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010491 [ALC888_3ST_HP] = {
Herton Ronaldo Krzesinskieea64192008-03-20 12:14:59 +010010492 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010493 .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010494 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10495 .dac_nids = alc883_dac_nids,
Claudio Matsuoka4723c022007-07-13 14:36:19 +020010496 .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
10497 .channel_mode = alc888_3st_hp_modes,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010498 .need_dac_fix = 1,
10499 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010500 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010501 .setup = alc888_3st_hp_setup,
10502 .init_hook = alc_automute_amp,
Claudio Matsuoka8341de62007-07-06 12:10:45 +020010503 },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010504 [ALC888_6ST_DELL] = {
Herton Ronaldo Krzesinskif24dbdc2008-03-20 12:14:28 +010010505 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010506 .init_verbs = { alc883_init_verbs, alc888_6st_dell_verbs },
10507 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10508 .dac_nids = alc883_dac_nids,
10509 .dig_out_nid = ALC883_DIGOUT_NID,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010510 .dig_in_nid = ALC883_DIGIN_NID,
10511 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10512 .channel_mode = alc883_sixstack_modes,
10513 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010514 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010515 .setup = alc888_6st_dell_setup,
10516 .init_hook = alc_automute_amp,
Claudio Matsuoka5795b9e2008-01-13 11:58:27 +010010517 },
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010518 [ALC883_MITAC] = {
10519 .mixers = { alc883_mitac_mixer },
10520 .init_verbs = { alc883_init_verbs, alc883_mitac_verbs },
10521 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10522 .dac_nids = alc883_dac_nids,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010523 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10524 .channel_mode = alc883_3ST_2ch_modes,
10525 .input_mux = &alc883_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010526 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010527 .setup = alc883_mitac_setup,
10528 .init_hook = alc_automute_amp,
Andy Shevchenkoa8848bd2007-12-13 17:32:26 +010010529 },
Jiang zhefb97dc62008-03-06 11:07:11 +010010530 [ALC883_FUJITSU_PI2515] = {
10531 .mixers = { alc883_2ch_fujitsu_pi2515_mixer },
10532 .init_verbs = { alc883_init_verbs,
10533 alc883_2ch_fujitsu_pi2515_verbs},
10534 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10535 .dac_nids = alc883_dac_nids,
10536 .dig_out_nid = ALC883_DIGOUT_NID,
10537 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10538 .channel_mode = alc883_3ST_2ch_modes,
10539 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010540 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010541 .setup = alc883_2ch_fujitsu_pi2515_setup,
10542 .init_hook = alc_automute_amp,
Jiang zhefb97dc62008-03-06 11:07:11 +010010543 },
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010544 [ALC888_FUJITSU_XA3530] = {
10545 .mixers = { alc888_base_mixer, alc883_chmode_mixer },
10546 .init_verbs = { alc883_init_verbs,
10547 alc888_fujitsu_xa3530_verbs },
10548 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10549 .dac_nids = alc883_dac_nids,
10550 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev),
10551 .adc_nids = alc883_adc_nids_rev,
10552 .capsrc_nids = alc883_capsrc_nids_rev,
10553 .dig_out_nid = ALC883_DIGOUT_NID,
10554 .num_channel_mode = ARRAY_SIZE(alc888_4ST_8ch_intel_modes),
10555 .channel_mode = alc888_4ST_8ch_intel_modes,
10556 .num_mux_defs =
10557 ARRAY_SIZE(alc888_2_capture_sources),
10558 .input_mux = alc888_2_capture_sources,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010559 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010560 .setup = alc888_fujitsu_xa3530_setup,
10561 .init_hook = alc_automute_amp,
Vincent Petryef8ef5f2008-11-23 11:31:41 +080010562 },
Kailang Yange2757d52008-08-26 13:17:46 +020010563 [ALC888_LENOVO_SKY] = {
10564 .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer },
10565 .init_verbs = { alc883_init_verbs, alc888_lenovo_sky_verbs},
10566 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10567 .dac_nids = alc883_dac_nids,
10568 .dig_out_nid = ALC883_DIGOUT_NID,
Kailang Yange2757d52008-08-26 13:17:46 +020010569 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10570 .channel_mode = alc883_sixstack_modes,
10571 .need_dac_fix = 1,
10572 .input_mux = &alc883_lenovo_sky_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010573 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010574 .setup = alc888_lenovo_sky_setup,
10575 .init_hook = alc_automute_amp,
Kailang Yange2757d52008-08-26 13:17:46 +020010576 },
10577 [ALC888_ASUS_M90V] = {
10578 .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer },
10579 .init_verbs = { alc883_init_verbs, alc888_asus_m90v_verbs },
10580 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10581 .dac_nids = alc883_dac_nids,
10582 .dig_out_nid = ALC883_DIGOUT_NID,
10583 .dig_in_nid = ALC883_DIGIN_NID,
10584 .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes),
10585 .channel_mode = alc883_3ST_6ch_modes,
10586 .need_dac_fix = 1,
10587 .input_mux = &alc883_fujitsu_pi2515_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010588 .unsol_event = alc_sku_unsol_event,
10589 .setup = alc883_mode2_setup,
10590 .init_hook = alc_inithook,
Kailang Yange2757d52008-08-26 13:17:46 +020010591 },
10592 [ALC888_ASUS_EEE1601] = {
10593 .mixers = { alc883_asus_eee1601_mixer },
Takashi Iwaif9e336f2008-10-31 16:37:07 +010010594 .cap_mixer = alc883_asus_eee1601_cap_mixer,
Kailang Yange2757d52008-08-26 13:17:46 +020010595 .init_verbs = { alc883_init_verbs, alc888_asus_eee1601_verbs },
10596 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10597 .dac_nids = alc883_dac_nids,
10598 .dig_out_nid = ALC883_DIGOUT_NID,
10599 .dig_in_nid = ALC883_DIGIN_NID,
10600 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10601 .channel_mode = alc883_3ST_2ch_modes,
10602 .need_dac_fix = 1,
10603 .input_mux = &alc883_asus_eee1601_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020010604 .unsol_event = alc_sku_unsol_event,
Kailang Yange2757d52008-08-26 13:17:46 +020010605 .init_hook = alc883_eee1601_inithook,
10606 },
Wu Fengguang3ab90932008-11-17 09:51:09 +010010607 [ALC1200_ASUS_P5Q] = {
10608 .mixers = { alc883_base_mixer, alc883_chmode_mixer },
10609 .init_verbs = { alc883_init_verbs },
10610 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10611 .dac_nids = alc883_dac_nids,
10612 .dig_out_nid = ALC1200_DIGOUT_NID,
10613 .dig_in_nid = ALC883_DIGIN_NID,
Wu Fengguangb25c9da2009-02-06 15:02:27 +080010614 .slave_dig_outs = alc1200_slave_dig_outs,
Wu Fengguang3ab90932008-11-17 09:51:09 +010010615 .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
10616 .channel_mode = alc883_sixstack_modes,
10617 .input_mux = &alc883_capture_source,
10618 },
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010619 [ALC889A_MB31] = {
10620 .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer},
10621 .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs,
10622 alc880_gpio1_init_verbs },
10623 .adc_nids = alc883_adc_nids,
10624 .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
Takashi Iwai035eb0c2009-12-17 15:00:26 +010010625 .capsrc_nids = alc883_capsrc_nids,
Torben Schulzeb4c41d2009-05-18 15:02:35 +020010626 .dac_nids = alc883_dac_nids,
10627 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10628 .channel_mode = alc889A_mb31_6ch_modes,
10629 .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes),
10630 .input_mux = &alc889A_mb31_capture_source,
10631 .dig_out_nid = ALC883_DIGOUT_NID,
10632 .unsol_event = alc889A_mb31_unsol_event,
10633 .init_hook = alc889A_mb31_automute,
10634 },
Guido Günther3e1647c2009-06-05 00:47:26 +020010635 [ALC883_SONY_VAIO_TT] = {
10636 .mixers = { alc883_vaiott_mixer },
10637 .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs },
10638 .num_dacs = ARRAY_SIZE(alc883_dac_nids),
10639 .dac_nids = alc883_dac_nids,
10640 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
10641 .channel_mode = alc883_3ST_2ch_modes,
10642 .input_mux = &alc883_capture_source,
10643 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020010644 .setup = alc883_vaiott_setup,
10645 .init_hook = alc_automute_amp,
Guido Günther3e1647c2009-06-05 00:47:26 +020010646 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010647};
10648
10649
10650/*
Takashi Iwai49535502009-06-30 15:28:30 +020010651 * Pin config fixes
10652 */
10653enum {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010654 PINFIX_ABIT_AW9D_MAX,
10655 PINFIX_PB_M5210,
David Henningssonc3d226a2010-10-14 15:42:08 +020010656 PINFIX_ACER_ASPIRE_7736,
Takashi Iwai49535502009-06-30 15:28:30 +020010657};
10658
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010659static const struct alc_fixup alc882_fixups[] = {
10660 [PINFIX_ABIT_AW9D_MAX] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020010661 .pins = (const struct alc_pincfg[]) {
10662 { 0x15, 0x01080104 }, /* side */
10663 { 0x16, 0x01011012 }, /* rear */
10664 { 0x17, 0x01016011 }, /* clfe */
10665 { }
10666 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010667 },
Takashi Iwai954a29c2010-07-30 10:55:44 +020010668 [PINFIX_PB_M5210] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020010669 .verbs = (const struct hda_verb[]) {
10670 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
10671 {}
10672 }
Takashi Iwai954a29c2010-07-30 10:55:44 +020010673 },
David Henningssonc3d226a2010-10-14 15:42:08 +020010674 [PINFIX_ACER_ASPIRE_7736] = {
10675 .sku = ALC_FIXUP_SKU_IGNORE,
10676 },
Takashi Iwai49535502009-06-30 15:28:30 +020010677};
10678
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020010679static struct snd_pci_quirk alc882_fixup_tbl[] = {
Takashi Iwai954a29c2010-07-30 10:55:44 +020010680 SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", PINFIX_PB_M5210),
Takashi Iwai49535502009-06-30 15:28:30 +020010681 SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
David Henningssonc3d226a2010-10-14 15:42:08 +020010682 SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", PINFIX_ACER_ASPIRE_7736),
Takashi Iwai49535502009-06-30 15:28:30 +020010683 {}
10684};
10685
10686/*
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010687 * BIOS auto configuration
10688 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020010689static int alc882_auto_create_input_ctls(struct hda_codec *codec,
10690 const struct auto_pin_cfg *cfg)
10691{
10692 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x23, 0x22);
10693}
10694
Takashi Iwai49535502009-06-30 15:28:30 +020010695static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010696 hda_nid_t nid, int pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010697 hda_nid_t dac)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010698{
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010699 int idx;
10700
Takashi Iwai489008c2010-04-07 09:06:00 +020010701 /* set as output */
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010702 alc_set_pin_output(codec, nid, pin_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010703
Takashi Iwai489008c2010-04-07 09:06:00 +020010704 if (dac == 0x25)
10705 idx = 4;
10706 else if (dac >= 0x02 && dac <= 0x05)
10707 idx = dac - 2;
10708 else
10709 return;
10710 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010711}
10712
Takashi Iwai49535502009-06-30 15:28:30 +020010713static void alc882_auto_init_multi_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010714{
10715 struct alc_spec *spec = codec->spec;
10716 int i;
10717
10718 for (i = 0; i <= HDA_SIDE; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010719 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020010720 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010721 if (nid)
Takashi Iwai49535502009-06-30 15:28:30 +020010722 alc882_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai489008c2010-04-07 09:06:00 +020010723 spec->multiout.dac_nids[i]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010724 }
10725}
10726
Takashi Iwai49535502009-06-30 15:28:30 +020010727static void alc882_auto_init_hp_out(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010728{
10729 struct alc_spec *spec = codec->spec;
Takashi Iwai489008c2010-04-07 09:06:00 +020010730 hda_nid_t pin, dac;
Takashi Iwai5855fb82010-09-16 18:24:02 +020010731 int i;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010732
Takashi Iwai5855fb82010-09-16 18:24:02 +020010733 for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) {
10734 pin = spec->autocfg.hp_pins[i];
10735 if (!pin)
10736 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010737 dac = spec->multiout.hp_nid;
10738 if (!dac)
10739 dac = spec->multiout.dac_nids[0]; /* to front */
10740 alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
10741 }
Takashi Iwai5855fb82010-09-16 18:24:02 +020010742 for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) {
10743 pin = spec->autocfg.speaker_pins[i];
10744 if (!pin)
10745 break;
Takashi Iwai489008c2010-04-07 09:06:00 +020010746 dac = spec->multiout.extra_out_nid[0];
10747 if (!dac)
10748 dac = spec->multiout.dac_nids[0]; /* to front */
10749 alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
10750 }
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010751}
10752
Takashi Iwai49535502009-06-30 15:28:30 +020010753static void alc882_auto_init_analog_input(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010754{
10755 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010756 struct auto_pin_cfg *cfg = &spec->autocfg;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010757 int i;
10758
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010759 for (i = 0; i < cfg->num_inputs; i++) {
10760 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai30ea0982010-09-16 18:47:56 +020010761 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai49535502009-06-30 15:28:30 +020010762 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
10763 snd_hda_codec_write(codec, nid, 0,
10764 AC_VERB_SET_AMP_GAIN_MUTE,
10765 AMP_OUT_MUTE);
10766 }
10767}
10768
10769static void alc882_auto_init_input_src(struct hda_codec *codec)
10770{
10771 struct alc_spec *spec = codec->spec;
10772 int c;
10773
10774 for (c = 0; c < spec->num_adc_nids; c++) {
10775 hda_nid_t conn_list[HDA_MAX_NUM_INPUTS];
10776 hda_nid_t nid = spec->capsrc_nids[c];
10777 unsigned int mux_idx;
10778 const struct hda_input_mux *imux;
10779 int conns, mute, idx, item;
10780
10781 conns = snd_hda_get_connections(codec, nid, conn_list,
10782 ARRAY_SIZE(conn_list));
10783 if (conns < 0)
10784 continue;
10785 mux_idx = c >= spec->num_mux_defs ? 0 : c;
10786 imux = &spec->input_mux[mux_idx];
Takashi Iwai53111142010-03-08 12:13:07 +010010787 if (!imux->num_items && mux_idx > 0)
10788 imux = &spec->input_mux[0];
Takashi Iwai49535502009-06-30 15:28:30 +020010789 for (idx = 0; idx < conns; idx++) {
10790 /* if the current connection is the selected one,
10791 * unmute it as default - otherwise mute it
10792 */
10793 mute = AMP_IN_MUTE(idx);
10794 for (item = 0; item < imux->num_items; item++) {
10795 if (imux->items[item].index == idx) {
10796 if (spec->cur_mux[c] == item)
10797 mute = AMP_IN_UNMUTE(idx);
10798 break;
10799 }
10800 }
10801 /* check if we have a selector or mixer
10802 * we could check for the widget type instead, but
10803 * just check for Amp-In presence (in case of mixer
10804 * without amp-in there is something wrong, this
10805 * function shouldn't be used or capsrc nid is wrong)
10806 */
10807 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010808 snd_hda_codec_write(codec, nid, 0,
10809 AC_VERB_SET_AMP_GAIN_MUTE,
Takashi Iwai49535502009-06-30 15:28:30 +020010810 mute);
10811 else if (mute != AMP_IN_MUTE(idx))
10812 snd_hda_codec_write(codec, nid, 0,
10813 AC_VERB_SET_CONNECT_SEL,
10814 idx);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010815 }
10816 }
10817}
10818
Takashi Iwai49535502009-06-30 15:28:30 +020010819/* add mic boosts if needed */
10820static int alc_auto_add_mic_boost(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010821{
10822 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010823 struct auto_pin_cfg *cfg = &spec->autocfg;
David Henningsson5322bf22011-01-05 11:03:56 +010010824 int i, err;
Takashi Iwai53e8c322010-12-17 15:23:41 +010010825 int type_idx = 0;
Takashi Iwai49535502009-06-30 15:28:30 +020010826 hda_nid_t nid;
David Henningsson5322bf22011-01-05 11:03:56 +010010827 const char *prev_label = NULL;
Takashi Iwai49535502009-06-30 15:28:30 +020010828
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010829 for (i = 0; i < cfg->num_inputs; i++) {
Takashi Iwai86e29592010-09-09 14:50:17 +020010830 if (cfg->inputs[i].type > AUTO_PIN_MIC)
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010831 break;
10832 nid = cfg->inputs[i].pin;
10833 if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
David Henningsson5322bf22011-01-05 11:03:56 +010010834 const char *label;
10835 char boost_label[32];
10836
10837 label = hda_get_autocfg_input_label(codec, cfg, i);
10838 if (prev_label && !strcmp(label, prev_label))
Takashi Iwai53e8c322010-12-17 15:23:41 +010010839 type_idx++;
10840 else
10841 type_idx = 0;
David Henningsson5322bf22011-01-05 11:03:56 +010010842 prev_label = label;
10843
10844 snprintf(boost_label, sizeof(boost_label),
10845 "%s Boost Volume", label);
10846 err = add_control(spec, ALC_CTL_WIDGET_VOL,
10847 boost_label, type_idx,
Takashi Iwai49535502009-06-30 15:28:30 +020010848 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
Takashi Iwai66ceeb62010-08-30 13:05:52 +020010849 if (err < 0)
10850 return err;
10851 }
Takashi Iwai49535502009-06-30 15:28:30 +020010852 }
10853 return 0;
10854}
10855
10856/* almost identical with ALC880 parser... */
10857static int alc882_parse_auto_config(struct hda_codec *codec)
10858{
10859 struct alc_spec *spec = codec->spec;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010860 static hda_nid_t alc882_ignore[] = { 0x1d, 0 };
Takashi Iwai757899a2010-07-30 10:48:14 +020010861 int err;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010862
Takashi Iwai05f5f472009-08-25 13:10:18 +020010863 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
10864 alc882_ignore);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010865 if (err < 0)
10866 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010867 if (!spec->autocfg.line_outs)
10868 return 0; /* can't find valid BIOS pin config */
10869
10870 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
10871 if (err < 0)
10872 return err;
10873 err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg);
10874 if (err < 0)
10875 return err;
Takashi Iwai489008c2010-04-07 09:06:00 +020010876 err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pins[0],
10877 "Headphone");
10878 if (err < 0)
10879 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010880 err = alc880_auto_create_extra_out(spec,
10881 spec->autocfg.speaker_pins[0],
10882 "Speaker");
10883 if (err < 0)
10884 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020010885 err = alc882_auto_create_input_ctls(codec, &spec->autocfg);
10886 if (err < 0)
10887 return err;
10888
10889 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
10890
Takashi Iwai757899a2010-07-30 10:48:14 +020010891 alc_auto_parse_digital(codec);
Takashi Iwai05f5f472009-08-25 13:10:18 +020010892
10893 if (spec->kctls.list)
10894 add_mixer(spec, spec->kctls.list);
10895
10896 add_verb(spec, alc883_auto_init_verbs);
10897 /* if ADC 0x07 is available, initialize it, too */
10898 if (get_wcaps_type(get_wcaps(codec, 0x07)) == AC_WID_AUD_IN)
10899 add_verb(spec, alc882_adc1_init_verbs);
10900
10901 spec->num_mux_defs = 1;
10902 spec->input_mux = &spec->private_imux[0];
10903
Kailang Yang6227cdc2010-02-25 08:36:52 +010010904 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai776e1842007-08-29 15:07:11 +020010905
10906 err = alc_auto_add_mic_boost(codec);
10907 if (err < 0)
10908 return err;
10909
Takashi Iwai776e1842007-08-29 15:07:11 +020010910 return 1; /* config found */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010911}
10912
10913/* additional initialization for auto-configuration model */
Takashi Iwai49535502009-06-30 15:28:30 +020010914static void alc882_auto_init(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010915{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010916 struct alc_spec *spec = codec->spec;
Takashi Iwai49535502009-06-30 15:28:30 +020010917 alc882_auto_init_multi_out(codec);
10918 alc882_auto_init_hp_out(codec);
10919 alc882_auto_init_analog_input(codec);
10920 alc882_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020010921 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010010922 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020010923 alc_inithook(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010924}
10925
Takashi Iwai49535502009-06-30 15:28:30 +020010926static int patch_alc882(struct hda_codec *codec)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010927{
10928 struct alc_spec *spec;
10929 int err, board_config;
10930
10931 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10932 if (spec == NULL)
10933 return -ENOMEM;
10934
10935 codec->spec = spec;
10936
Takashi Iwai49535502009-06-30 15:28:30 +020010937 switch (codec->vendor_id) {
10938 case 0x10ec0882:
10939 case 0x10ec0885:
10940 break;
10941 default:
10942 /* ALC883 and variants */
10943 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
10944 break;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010945 }
10946
Takashi Iwai49535502009-06-30 15:28:30 +020010947 board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST,
10948 alc882_models,
10949 alc882_cfg_tbl);
10950
10951 if (board_config < 0 || board_config >= ALC882_MODEL_LAST)
10952 board_config = snd_hda_check_board_codec_sid_config(codec,
10953 ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
10954
10955 if (board_config < 0 || board_config >= ALC882_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020010956 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
Takashi Iwai49535502009-06-30 15:28:30 +020010957 codec->chip_name);
10958 board_config = ALC882_AUTO;
10959 }
10960
Takashi Iwai7fa90e82010-04-12 08:49:00 +020010961 if (board_config == ALC882_AUTO)
10962 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1);
Takashi Iwai49535502009-06-30 15:28:30 +020010963
David Henningsson90622912010-10-14 14:50:18 +020010964 alc_auto_parse_customize_define(codec);
10965
Takashi Iwai49535502009-06-30 15:28:30 +020010966 if (board_config == ALC882_AUTO) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010967 /* automatic parse from the BIOS config */
Takashi Iwai49535502009-06-30 15:28:30 +020010968 err = alc882_parse_auto_config(codec);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010969 if (err < 0) {
10970 alc_free(codec);
10971 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020010972 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010973 printk(KERN_INFO
10974 "hda_codec: Cannot set up configuration "
10975 "from BIOS. Using base mode...\n");
Takashi Iwai49535502009-06-30 15:28:30 +020010976 board_config = ALC882_3ST_DIG;
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010977 }
10978 }
10979
Takashi Iwaidc1eae22010-07-29 15:30:02 +020010980 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020010981 err = snd_hda_attach_beep_device(codec, 0x1);
10982 if (err < 0) {
10983 alc_free(codec);
10984 return err;
10985 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090010986 }
10987
Takashi Iwai49535502009-06-30 15:28:30 +020010988 if (board_config != ALC882_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020010989 setup_preset(codec, &alc882_presets[board_config]);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020010990
Takashi Iwai49535502009-06-30 15:28:30 +020010991 spec->stream_analog_playback = &alc882_pcm_analog_playback;
10992 spec->stream_analog_capture = &alc882_pcm_analog_capture;
10993 /* FIXME: setup DAC5 */
10994 /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/
10995 spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture;
10996
10997 spec->stream_digital_playback = &alc882_pcm_digital_playback;
10998 spec->stream_digital_capture = &alc882_pcm_digital_capture;
10999
Takashi Iwai49535502009-06-30 15:28:30 +020011000 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011001 int i, j;
Takashi Iwai49535502009-06-30 15:28:30 +020011002 spec->num_adc_nids = 0;
11003 for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) {
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011004 const struct hda_input_mux *imux = spec->input_mux;
Takashi Iwai49535502009-06-30 15:28:30 +020011005 hda_nid_t cap;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011006 hda_nid_t items[16];
Takashi Iwai49535502009-06-30 15:28:30 +020011007 hda_nid_t nid = alc882_adc_nids[i];
11008 unsigned int wcap = get_wcaps(codec, nid);
11009 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020011010 wcap = get_wcaps_type(wcap);
Takashi Iwai49535502009-06-30 15:28:30 +020011011 if (wcap != AC_WID_AUD_IN)
11012 continue;
11013 spec->private_adc_nids[spec->num_adc_nids] = nid;
11014 err = snd_hda_get_connections(codec, nid, &cap, 1);
11015 if (err < 0)
11016 continue;
Takashi Iwaid11f74c2009-12-08 12:52:47 +010011017 err = snd_hda_get_connections(codec, cap, items,
11018 ARRAY_SIZE(items));
11019 if (err < 0)
11020 continue;
11021 for (j = 0; j < imux->num_items; j++)
11022 if (imux->items[j].index >= err)
11023 break;
11024 if (j < imux->num_items)
11025 continue;
Takashi Iwai49535502009-06-30 15:28:30 +020011026 spec->private_capsrc_nids[spec->num_adc_nids] = cap;
11027 spec->num_adc_nids++;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020011028 }
Takashi Iwai49535502009-06-30 15:28:30 +020011029 spec->adc_nids = spec->private_adc_nids;
11030 spec->capsrc_nids = spec->private_capsrc_nids;
Kailang Yang2f893282008-05-27 12:14:47 +020011031 }
11032
Takashi Iwaib59bdf32009-08-11 09:47:30 +020011033 set_capture_mixer(codec);
Kailang Yangda00c242010-03-19 11:23:45 +010011034
Takashi Iwaidc1eae22010-07-29 15:30:02 +020011035 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010011036 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011037
Takashi Iwai7fa90e82010-04-12 08:49:00 +020011038 if (board_config == ALC882_AUTO)
11039 alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0);
11040
Takashi Iwai2134ea42008-01-10 16:53:55 +010011041 spec->vmaster_nid = 0x0c;
11042
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011043 codec->patch_ops = alc_patch_ops;
Takashi Iwai49535502009-06-30 15:28:30 +020011044 if (board_config == ALC882_AUTO)
11045 spec->init_hook = alc882_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020011046
11047 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020011048#ifdef CONFIG_SND_HDA_POWER_SAVE
11049 if (!spec->loopback.amplist)
Takashi Iwai49535502009-06-30 15:28:30 +020011050 spec->loopback.amplist = alc882_loopbacks;
Takashi Iwaicb53c622007-08-10 17:21:45 +020011051#endif
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011052
11053 return 0;
11054}
11055
Takashi Iwai49535502009-06-30 15:28:30 +020011056
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011057/*
Kailang Yangdf694da2005-12-05 19:42:22 +010011058 * ALC262 support
11059 */
11060
11061#define ALC262_DIGOUT_NID ALC880_DIGOUT_NID
11062#define ALC262_DIGIN_NID ALC880_DIGIN_NID
11063
11064#define alc262_dac_nids alc260_dac_nids
11065#define alc262_adc_nids alc882_adc_nids
11066#define alc262_adc_nids_alt alc882_adc_nids_alt
Takashi Iwai88c71a92008-02-14 17:27:17 +010011067#define alc262_capsrc_nids alc882_capsrc_nids
11068#define alc262_capsrc_nids_alt alc882_capsrc_nids_alt
Kailang Yangdf694da2005-12-05 19:42:22 +010011069
11070#define alc262_modes alc260_modes
Takashi Iwaic5f2ea02005-12-06 18:54:31 +010011071#define alc262_capture_source alc882_capture_source
Kailang Yangdf694da2005-12-05 19:42:22 +010011072
Kailang Yang4e555fe2008-08-26 13:05:55 +020011073static hda_nid_t alc262_dmic_adc_nids[1] = {
11074 /* ADC0 */
11075 0x09
11076};
11077
11078static hda_nid_t alc262_dmic_capsrc_nids[1] = { 0x22 };
11079
Kailang Yangdf694da2005-12-05 19:42:22 +010011080static struct snd_kcontrol_new alc262_base_mixer[] = {
11081 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11082 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11083 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11084 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11085 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11086 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11087 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11088 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011089 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011090 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11091 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011092 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011093 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),
11094 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11095 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
11096 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
Kailang Yangdf694da2005-12-05 19:42:22 +010011097 { } /* end */
Takashi Iwai834be882006-03-01 14:16:17 +010011098};
11099
Takashi Iwaice875f02008-01-28 18:17:43 +010011100/* update HP, line and mono-out pins according to the master switch */
11101static void alc262_hp_master_update(struct hda_codec *codec)
11102{
11103 struct alc_spec *spec = codec->spec;
11104 int val = spec->master_sw;
11105
11106 /* HP & line-out */
11107 snd_hda_codec_write_cache(codec, 0x1b, 0,
11108 AC_VERB_SET_PIN_WIDGET_CONTROL,
11109 val ? PIN_HP : 0);
11110 snd_hda_codec_write_cache(codec, 0x15, 0,
11111 AC_VERB_SET_PIN_WIDGET_CONTROL,
11112 val ? PIN_HP : 0);
11113 /* mono (speaker) depending on the HP jack sense */
11114 val = val && !spec->jack_present;
11115 snd_hda_codec_write_cache(codec, 0x16, 0,
11116 AC_VERB_SET_PIN_WIDGET_CONTROL,
11117 val ? PIN_OUT : 0);
11118}
11119
11120static void alc262_hp_bpc_automute(struct hda_codec *codec)
11121{
11122 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011123
11124 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwaice875f02008-01-28 18:17:43 +010011125 alc262_hp_master_update(codec);
11126}
11127
11128static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res)
11129{
11130 if ((res >> 26) != ALC880_HP_EVENT)
11131 return;
11132 alc262_hp_bpc_automute(codec);
11133}
11134
11135static void alc262_hp_wildwest_automute(struct hda_codec *codec)
11136{
11137 struct alc_spec *spec = codec->spec;
Wu Fengguang864f92b2009-11-18 12:38:02 +080011138
11139 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaice875f02008-01-28 18:17:43 +010011140 alc262_hp_master_update(codec);
11141}
11142
11143static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec,
11144 unsigned int res)
11145{
11146 if ((res >> 26) != ALC880_HP_EVENT)
11147 return;
11148 alc262_hp_wildwest_automute(codec);
11149}
11150
Takashi Iwaib72519b2009-05-08 14:31:55 +020011151#define alc262_hp_master_sw_get alc260_hp_master_sw_get
Takashi Iwaice875f02008-01-28 18:17:43 +010011152
11153static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol,
11154 struct snd_ctl_elem_value *ucontrol)
11155{
11156 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11157 struct alc_spec *spec = codec->spec;
11158 int val = !!*ucontrol->value.integer.value;
11159
11160 if (val == spec->master_sw)
11161 return 0;
11162 spec->master_sw = val;
11163 alc262_hp_master_update(codec);
11164 return 1;
11165}
11166
Takashi Iwaib72519b2009-05-08 14:31:55 +020011167#define ALC262_HP_MASTER_SWITCH \
11168 { \
11169 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11170 .name = "Master Playback Switch", \
11171 .info = snd_ctl_boolean_mono_info, \
11172 .get = alc262_hp_master_sw_get, \
11173 .put = alc262_hp_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011174 }, \
11175 { \
11176 .iface = NID_MAPPING, \
11177 .name = "Master Playback Switch", \
11178 .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \
Takashi Iwaib72519b2009-05-08 14:31:55 +020011179 }
11180
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011181
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011182static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011183 ALC262_HP_MASTER_SWITCH,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011184 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11185 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11186 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011187 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11188 HDA_OUTPUT),
11189 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11190 HDA_OUTPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011191 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11192 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011193 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011194 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11195 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011196 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011197 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11198 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11199 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11200 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011201 HDA_CODEC_VOLUME("AUX IN Playback Volume", 0x0b, 0x06, HDA_INPUT),
11202 HDA_CODEC_MUTE("AUX IN Playback Switch", 0x0b, 0x06, HDA_INPUT),
11203 { } /* end */
11204};
11205
Kailang Yangcd7509a2007-01-26 18:33:17 +010011206static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = {
Takashi Iwaib72519b2009-05-08 14:31:55 +020011207 ALC262_HP_MASTER_SWITCH,
Kailang Yangcd7509a2007-01-26 18:33:17 +010011208 HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11209 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
11210 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11211 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Takashi Iwaice875f02008-01-28 18:17:43 +010011212 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 2, 0x0,
11213 HDA_OUTPUT),
11214 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 2, 0x0,
11215 HDA_OUTPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011216 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x02, HDA_INPUT),
11217 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011218 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011219 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11220 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11221 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11222 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011223 { } /* end */
11224};
11225
11226static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = {
11227 HDA_CODEC_VOLUME("Rear Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11228 HDA_CODEC_MUTE("Rear Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011229 HDA_CODEC_VOLUME("Rear Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangcd7509a2007-01-26 18:33:17 +010011230 { } /* end */
11231};
11232
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011233/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011234static void alc262_hp_t5735_setup(struct hda_codec *codec)
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011235{
11236 struct alc_spec *spec = codec->spec;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011237
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011238 spec->autocfg.hp_pins[0] = 0x15;
Takashi Iwaidc99be42010-01-20 08:35:06 +010011239 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011240}
11241
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011242static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = {
Takashi Iwai86cd9292008-01-28 18:09:56 +010011243 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11244 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011245 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11246 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11247 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11248 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011249 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010011250 { } /* end */
11251};
11252
11253static struct hda_verb alc262_hp_t5735_verbs[] = {
11254 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11255 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11256
11257 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
11258 { }
11259};
11260
Kailang Yang8c427222008-01-10 13:03:59 +010011261static struct snd_kcontrol_new alc262_hp_rp5700_mixer[] = {
Takashi Iwaif2f48e12008-01-28 18:14:43 +010011262 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11263 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010011264 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
11265 HDA_CODEC_MUTE("Speaker Playback Switch", 0x16, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010011266 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT),
11267 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT),
11268 { } /* end */
11269};
11270
11271static struct hda_verb alc262_hp_rp5700_verbs[] = {
11272 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11273 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11274 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11275 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11276 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11277 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11278 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11279 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
11280 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11281 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x00 << 8))},
11282 {}
11283};
11284
11285static struct hda_input_mux alc262_hp_rp5700_capture_source = {
11286 .num_items = 1,
11287 .items = {
11288 { "Line", 0x1 },
11289 },
11290};
11291
Takashi Iwai42171c12009-05-08 14:11:43 +020011292/* bind hp and internal speaker mute (with plug check) as master switch */
11293static void alc262_hippo_master_update(struct hda_codec *codec)
11294{
11295 struct alc_spec *spec = codec->spec;
11296 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
11297 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
11298 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
11299 unsigned int mute;
11300
11301 /* HP */
11302 mute = spec->master_sw ? 0 : HDA_AMP_MUTE;
11303 snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0,
11304 HDA_AMP_MUTE, mute);
11305 /* mute internal speaker per jack sense */
11306 if (spec->jack_present)
11307 mute = HDA_AMP_MUTE;
11308 if (line_nid)
11309 snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0,
11310 HDA_AMP_MUTE, mute);
11311 if (speaker_nid && speaker_nid != line_nid)
11312 snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0,
11313 HDA_AMP_MUTE, mute);
11314}
11315
11316#define alc262_hippo_master_sw_get alc262_hp_master_sw_get
11317
11318static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol,
11319 struct snd_ctl_elem_value *ucontrol)
Takashi Iwai0724ea22007-08-23 00:31:43 +020011320{
11321 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai42171c12009-05-08 14:11:43 +020011322 struct alc_spec *spec = codec->spec;
11323 int val = !!*ucontrol->value.integer.value;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011324
Takashi Iwai42171c12009-05-08 14:11:43 +020011325 if (val == spec->master_sw)
11326 return 0;
11327 spec->master_sw = val;
11328 alc262_hippo_master_update(codec);
11329 return 1;
Takashi Iwai0724ea22007-08-23 00:31:43 +020011330}
Takashi Iwai5b319542007-07-26 11:49:22 +020011331
Takashi Iwai42171c12009-05-08 14:11:43 +020011332#define ALC262_HIPPO_MASTER_SWITCH \
11333 { \
11334 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
11335 .name = "Master Playback Switch", \
11336 .info = snd_ctl_boolean_mono_info, \
11337 .get = alc262_hippo_master_sw_get, \
11338 .put = alc262_hippo_master_sw_put, \
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011339 }, \
11340 { \
11341 .iface = NID_MAPPING, \
11342 .name = "Master Playback Switch", \
11343 .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \
11344 (SUBDEV_SPEAKER(0) << 16), \
Takashi Iwai42171c12009-05-08 14:11:43 +020011345 }
11346
11347static struct snd_kcontrol_new alc262_hippo_mixer[] = {
11348 ALC262_HIPPO_MASTER_SWITCH,
11349 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11350 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11351 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11352 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11353 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11354 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11355 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011356 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011357 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11358 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011359 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011360 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11361 { } /* end */
11362};
11363
11364static struct snd_kcontrol_new alc262_hippo1_mixer[] = {
11365 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11366 ALC262_HIPPO_MASTER_SWITCH,
11367 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11368 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
11369 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11370 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11371 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11372 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011373 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011374 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11375 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011376 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011377 { } /* end */
11378};
11379
11380/* mute/unmute internal speaker according to the hp jack and mute state */
11381static void alc262_hippo_automute(struct hda_codec *codec)
11382{
11383 struct alc_spec *spec = codec->spec;
11384 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
Takashi Iwai42171c12009-05-08 14:11:43 +020011385
Wu Fengguang864f92b2009-11-18 12:38:02 +080011386 spec->jack_present = snd_hda_jack_detect(codec, hp_nid);
Takashi Iwai42171c12009-05-08 14:11:43 +020011387 alc262_hippo_master_update(codec);
11388}
11389
11390static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res)
11391{
11392 if ((res >> 26) != ALC880_HP_EVENT)
11393 return;
11394 alc262_hippo_automute(codec);
11395}
11396
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011397static void alc262_hippo_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011398{
11399 struct alc_spec *spec = codec->spec;
11400
11401 spec->autocfg.hp_pins[0] = 0x15;
11402 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011403}
11404
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011405static void alc262_hippo1_setup(struct hda_codec *codec)
Takashi Iwai42171c12009-05-08 14:11:43 +020011406{
11407 struct alc_spec *spec = codec->spec;
11408
11409 spec->autocfg.hp_pins[0] = 0x1b;
11410 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai42171c12009-05-08 14:11:43 +020011411}
11412
11413
Kailang Yang272a5272007-05-14 11:00:38 +020011414static struct snd_kcontrol_new alc262_sony_mixer[] = {
Takashi Iwai0724ea22007-08-23 00:31:43 +020011415 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020011416 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang272a5272007-05-14 11:00:38 +020011417 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11418 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11419 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11420 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11421 { } /* end */
11422};
11423
Kailang Yang83c34212007-07-05 11:43:05 +020011424static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020011425 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11426 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang83c34212007-07-05 11:43:05 +020011427 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11428 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11429 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
11430 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11431 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
11432 { } /* end */
11433};
Kailang Yang272a5272007-05-14 11:00:38 +020011434
Tony Vroonba340e82009-02-02 19:01:30 +000011435static struct snd_kcontrol_new alc262_tyan_mixer[] = {
11436 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11437 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
11438 HDA_CODEC_VOLUME("Aux Playback Volume", 0x0b, 0x06, HDA_INPUT),
11439 HDA_CODEC_MUTE("Aux Playback Switch", 0x0b, 0x06, HDA_INPUT),
11440 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
11441 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
11442 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11443 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011444 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011445 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11446 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011447 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroonba340e82009-02-02 19:01:30 +000011448 { } /* end */
11449};
11450
11451static struct hda_verb alc262_tyan_verbs[] = {
11452 /* Headphone automute */
11453 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11454 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11455 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11456
11457 /* P11 AUX_IN, white 4-pin connector */
11458 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11459 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_1, 0xe1},
11460 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_2, 0x93},
11461 {0x14, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0x19},
11462
11463 {}
11464};
11465
11466/* unsolicited event for HP jack sensing */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011467static void alc262_tyan_setup(struct hda_codec *codec)
Tony Vroonba340e82009-02-02 19:01:30 +000011468{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011469 struct alc_spec *spec = codec->spec;
Tony Vroonba340e82009-02-02 19:01:30 +000011470
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011471 spec->autocfg.hp_pins[0] = 0x1b;
11472 spec->autocfg.speaker_pins[0] = 0x15;
Tony Vroonba340e82009-02-02 19:01:30 +000011473}
11474
Tony Vroonba340e82009-02-02 19:01:30 +000011475
Kailang Yangdf694da2005-12-05 19:42:22 +010011476#define alc262_capture_mixer alc882_capture_mixer
11477#define alc262_capture_alt_mixer alc882_capture_alt_mixer
11478
11479/*
11480 * generic initialization of ADC, input mixers and output mixers
11481 */
11482static struct hda_verb alc262_init_verbs[] = {
11483 /*
11484 * Unmute ADC0-2 and set the default input to mic-in
11485 */
11486 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
11487 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11488 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
11489 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11490 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
11491 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11492
Takashi Iwaicb53c622007-08-10 17:21:45 +020011493 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010011494 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011495 * Note: PASD motherboards uses the Line In 2 as the input for
11496 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010011497 */
11498 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020011499 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11500 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11501 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11502 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11503 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010011504
11505 /*
11506 * Set up output mixers (0x0c - 0x0e)
11507 */
11508 /* set vol=0 to output mixers */
11509 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11510 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11511 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11512 /* set up input amps for analog loopback */
11513 /* Amp Indices: DAC = 0, mixer = 1 */
11514 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11515 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11516 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11517 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11518 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11519 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11520
11521 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11522 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11523 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
11524 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11525 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11526 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
11527
11528 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11529 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11530 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11531 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11532 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
Kailang Yangea1fb292008-08-26 12:58:38 +020011533
Kailang Yangdf694da2005-12-05 19:42:22 +010011534 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11535 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
Kailang Yangea1fb292008-08-26 12:58:38 +020011536
Kailang Yangdf694da2005-12-05 19:42:22 +010011537 /* FIXME: use matrix-type input source selection */
11538 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
11539 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
11540 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11541 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11542 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11543 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11544 /* Input mixer2 */
11545 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11546 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11547 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
11548 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
11549 /* Input mixer3 */
11550 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
11551 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
11552 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011553 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
Kailang Yangdf694da2005-12-05 19:42:22 +010011554
11555 { }
11556};
11557
Kailang Yang4e555fe2008-08-26 13:05:55 +020011558static struct hda_verb alc262_eapd_verbs[] = {
11559 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
11560 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
11561 { }
11562};
11563
Kailang Yangccc656c2006-10-17 12:32:26 +020011564static struct hda_verb alc262_hippo1_unsol_verbs[] = {
11565 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11566 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
11567 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0x0000},
11568
11569 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11570 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11571 {}
11572};
11573
Kailang Yang272a5272007-05-14 11:00:38 +020011574static struct hda_verb alc262_sony_unsol_verbs[] = {
11575 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
11576 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11577 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, // Front Mic
11578
11579 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11580 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Akio Idehara7b1e8792008-06-09 22:46:07 +090011581 {}
Kailang Yang272a5272007-05-14 11:00:38 +020011582};
11583
Kailang Yang4e555fe2008-08-26 13:05:55 +020011584static struct snd_kcontrol_new alc262_toshiba_s06_mixer[] = {
11585 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11586 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
11587 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11588 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11589 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang4e555fe2008-08-26 13:05:55 +020011590 { } /* end */
11591};
11592
11593static struct hda_verb alc262_toshiba_s06_verbs[] = {
11594 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
11595 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11596 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11597 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11598 {0x22, AC_VERB_SET_CONNECT_SEL, 0x09},
11599 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11600 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
11601 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11602 {}
11603};
11604
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011605static void alc262_toshiba_s06_setup(struct hda_codec *codec)
Kailang Yang4e555fe2008-08-26 13:05:55 +020011606{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020011607 struct alc_spec *spec = codec->spec;
11608
11609 spec->autocfg.hp_pins[0] = 0x15;
11610 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020011611 spec->ext_mic.pin = 0x18;
11612 spec->ext_mic.mux_idx = 0;
11613 spec->int_mic.pin = 0x12;
11614 spec->int_mic.mux_idx = 9;
11615 spec->auto_mic = 1;
Kailang Yang4e555fe2008-08-26 13:05:55 +020011616}
11617
Takashi Iwai834be882006-03-01 14:16:17 +010011618/*
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011619 * nec model
11620 * 0x15 = headphone
11621 * 0x16 = internal speaker
11622 * 0x18 = external mic
11623 */
11624
11625static struct snd_kcontrol_new alc262_nec_mixer[] = {
11626 HDA_CODEC_VOLUME_MONO("Speaker Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
11627 HDA_CODEC_MUTE_MONO("Speaker Playback Switch", 0x16, 0, 0x0, HDA_OUTPUT),
11628
11629 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11630 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011631 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020011632
11633 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT),
11634 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
11635 { } /* end */
11636};
11637
11638static struct hda_verb alc262_nec_verbs[] = {
11639 /* Unmute Speaker */
11640 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
11641
11642 /* Headphone */
11643 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11644 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11645
11646 /* External mic to headphone */
11647 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11648 /* External mic to speaker */
11649 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11650 {}
11651};
11652
11653/*
Takashi Iwai834be882006-03-01 14:16:17 +010011654 * fujitsu model
Tony Vroon5d9fab22008-03-14 17:09:18 +010011655 * 0x14 = headphone/spdif-out, 0x15 = internal speaker,
11656 * 0x1b = port replicator headphone out
Takashi Iwai834be882006-03-01 14:16:17 +010011657 */
11658
11659#define ALC_HP_EVENT 0x37
11660
11661static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
11662 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11663 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Tony Vroon5d9fab22008-03-14 17:09:18 +010011664 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11665 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai834be882006-03-01 14:16:17 +010011666 {}
11667};
11668
Jiang zhe0e31daf2008-03-20 12:12:39 +010011669static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = {
11670 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
11671 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
11672 {}
11673};
11674
Daniel T Chene2595322009-12-19 18:19:02 -050011675static struct hda_verb alc262_lenovo_3000_init_verbs[] = {
11676 /* Front Mic pin: input vref at 50% */
11677 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
11678 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11679 {}
11680};
11681
Takashi Iwai834be882006-03-01 14:16:17 +010011682static struct hda_input_mux alc262_fujitsu_capture_source = {
Takashi Iwai39d3ed32007-10-12 15:03:48 +020011683 .num_items = 3,
Takashi Iwai834be882006-03-01 14:16:17 +010011684 .items = {
11685 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010011686 { "Internal Mic", 0x1 },
Takashi Iwai834be882006-03-01 14:16:17 +010011687 { "CD", 0x4 },
11688 },
11689};
11690
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011691static struct hda_input_mux alc262_HP_capture_source = {
11692 .num_items = 5,
11693 .items = {
11694 { "Mic", 0x0 },
zhejiangaccbe492007-08-31 12:36:05 +020011695 { "Front Mic", 0x1 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020011696 { "Line", 0x2 },
11697 { "CD", 0x4 },
11698 { "AUX IN", 0x6 },
11699 },
11700};
11701
zhejiangaccbe492007-08-31 12:36:05 +020011702static struct hda_input_mux alc262_HP_D7000_capture_source = {
11703 .num_items = 4,
11704 .items = {
11705 { "Mic", 0x0 },
11706 { "Front Mic", 0x2 },
11707 { "Line", 0x1 },
11708 { "CD", 0x4 },
11709 },
11710};
11711
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011712/* mute/unmute internal speaker according to the hp jacks and mute state */
Takashi Iwai834be882006-03-01 14:16:17 +010011713static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
11714{
11715 struct alc_spec *spec = codec->spec;
11716 unsigned int mute;
11717
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020011718 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011719 spec->jack_present = snd_hda_jack_detect(codec, 0x14) ||
11720 snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai834be882006-03-01 14:16:17 +010011721 spec->sense_updated = 1;
11722 }
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011723 /* unmute internal speaker only if both HPs are unplugged and
11724 * master switch is on
11725 */
11726 if (spec->jack_present)
11727 mute = HDA_AMP_MUTE;
11728 else
Takashi Iwai834be882006-03-01 14:16:17 +010011729 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011730 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11731 HDA_AMP_MUTE, mute);
Takashi Iwai834be882006-03-01 14:16:17 +010011732}
11733
11734/* unsolicited event for HP jack sensing */
11735static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
11736 unsigned int res)
11737{
11738 if ((res >> 26) != ALC_HP_EVENT)
11739 return;
11740 alc262_fujitsu_automute(codec, 1);
11741}
11742
Takashi Iwaiebc7a402008-05-20 09:23:05 +020011743static void alc262_fujitsu_init_hook(struct hda_codec *codec)
11744{
11745 alc262_fujitsu_automute(codec, 1);
11746}
11747
Takashi Iwai834be882006-03-01 14:16:17 +010011748/* bind volumes of both NID 0x0c and 0x0d */
Takashi Iwaicca3b372007-08-10 17:12:15 +020011749static struct hda_bind_ctls alc262_fujitsu_bind_master_vol = {
11750 .ops = &snd_hda_bind_vol,
11751 .values = {
11752 HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
11753 HDA_COMPOSE_AMP_VAL(0x0d, 3, 0, HDA_OUTPUT),
11754 0
11755 },
11756};
Takashi Iwai834be882006-03-01 14:16:17 +010011757
Jiang zhe0e31daf2008-03-20 12:12:39 +010011758/* mute/unmute internal speaker according to the hp jack and mute state */
11759static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force)
11760{
11761 struct alc_spec *spec = codec->spec;
11762 unsigned int mute;
11763
11764 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011765 spec->jack_present = snd_hda_jack_detect(codec, 0x1b);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011766 spec->sense_updated = 1;
11767 }
11768 if (spec->jack_present) {
11769 /* mute internal speaker */
11770 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11771 HDA_AMP_MUTE, HDA_AMP_MUTE);
11772 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11773 HDA_AMP_MUTE, HDA_AMP_MUTE);
11774 } else {
11775 /* unmute internal speaker if necessary */
11776 mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0);
11777 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11778 HDA_AMP_MUTE, mute);
11779 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
11780 HDA_AMP_MUTE, mute);
11781 }
11782}
11783
11784/* unsolicited event for HP jack sensing */
11785static void alc262_lenovo_3000_unsol_event(struct hda_codec *codec,
11786 unsigned int res)
11787{
11788 if ((res >> 26) != ALC_HP_EVENT)
11789 return;
11790 alc262_lenovo_3000_automute(codec, 1);
11791}
11792
Takashi Iwai8de56b72009-07-24 16:51:47 +020011793static int amp_stereo_mute_update(struct hda_codec *codec, hda_nid_t nid,
11794 int dir, int idx, long *valp)
11795{
11796 int i, change = 0;
11797
11798 for (i = 0; i < 2; i++, valp++)
11799 change |= snd_hda_codec_amp_update(codec, nid, i, dir, idx,
11800 HDA_AMP_MUTE,
11801 *valp ? 0 : HDA_AMP_MUTE);
11802 return change;
11803}
11804
Takashi Iwai834be882006-03-01 14:16:17 +010011805/* bind hp and internal speaker mute (with plug check) */
11806static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
11807 struct snd_ctl_elem_value *ucontrol)
11808{
11809 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11810 long *valp = ucontrol->value.integer.value;
11811 int change;
11812
Takashi Iwai8de56b72009-07-24 16:51:47 +020011813 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
11814 change |= amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Takashi Iwai82beb8f2007-08-10 17:09:26 +020011815 if (change)
11816 alc262_fujitsu_automute(codec, 0);
Takashi Iwai834be882006-03-01 14:16:17 +010011817 return change;
11818}
11819
11820static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +020011821 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai834be882006-03-01 14:16:17 +010011822 {
11823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11824 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011825 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai834be882006-03-01 14:16:17 +010011826 .info = snd_hda_mixer_amp_switch_info,
11827 .get = snd_hda_mixer_amp_switch_get,
11828 .put = alc262_fujitsu_master_sw_put,
11829 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
11830 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010011831 {
11832 .iface = NID_MAPPING,
11833 .name = "Master Playback Switch",
11834 .private_value = 0x1b,
11835 },
Takashi Iwai834be882006-03-01 14:16:17 +010011836 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11837 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011838 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011839 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11840 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011841 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011842 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11843 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Takashi Iwai834be882006-03-01 14:16:17 +010011844 { } /* end */
11845};
11846
Jiang zhe0e31daf2008-03-20 12:12:39 +010011847/* bind hp and internal speaker mute (with plug check) */
11848static int alc262_lenovo_3000_master_sw_put(struct snd_kcontrol *kcontrol,
11849 struct snd_ctl_elem_value *ucontrol)
11850{
11851 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11852 long *valp = ucontrol->value.integer.value;
11853 int change;
11854
Takashi Iwai8de56b72009-07-24 16:51:47 +020011855 change = amp_stereo_mute_update(codec, 0x1b, HDA_OUTPUT, 0, valp);
Jiang zhe0e31daf2008-03-20 12:12:39 +010011856 if (change)
11857 alc262_lenovo_3000_automute(codec, 0);
11858 return change;
11859}
11860
11861static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = {
11862 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
11863 {
11864 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
11865 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010011866 .subdevice = HDA_SUBDEV_AMP_FLAG,
Jiang zhe0e31daf2008-03-20 12:12:39 +010011867 .info = snd_hda_mixer_amp_switch_info,
11868 .get = snd_hda_mixer_amp_switch_get,
11869 .put = alc262_lenovo_3000_master_sw_put,
11870 .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
11871 },
11872 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
11873 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011874 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011875 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11876 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011877 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010011878 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
11879 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Jiang zhe0e31daf2008-03-20 12:12:39 +010011880 { } /* end */
11881};
11882
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011883static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = {
11884 HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol),
Takashi Iwai42171c12009-05-08 14:11:43 +020011885 ALC262_HIPPO_MASTER_SWITCH,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011886 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
11887 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011888 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011889 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11890 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011891 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Hiroshi Miura9f99a632008-08-28 16:09:06 +020011892 { } /* end */
11893};
11894
Takashi Iwai304dcaa2006-07-25 14:51:16 +020011895/* additional init verbs for Benq laptops */
11896static struct hda_verb alc262_EAPD_verbs[] = {
11897 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11898 {0x20, AC_VERB_SET_PROC_COEF, 0x3070},
11899 {}
11900};
11901
Kailang Yang83c34212007-07-05 11:43:05 +020011902static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
11903 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11904 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
11905
11906 {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
11907 {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
11908 {}
11909};
11910
Tobin Davisf651b502007-10-26 12:40:47 +020011911/* Samsung Q1 Ultra Vista model setup */
11912static struct snd_kcontrol_new alc262_ultra_mixer[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011913 HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
11914 HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011915 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
11916 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010011917 HDA_CODEC_VOLUME("Mic Boost Volume", 0x19, 0, HDA_INPUT),
11918 HDA_CODEC_VOLUME("Headphone Mic Boost Volume", 0x15, 0, HDA_INPUT),
Tobin Davisf651b502007-10-26 12:40:47 +020011919 { } /* end */
11920};
11921
11922static struct hda_verb alc262_ultra_verbs[] = {
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011923 /* output mixer */
11924 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11925 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11926 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
11927 /* speaker */
11928 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
11929 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11930 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11931 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
11932 /* HP */
Tobin Davisf651b502007-10-26 12:40:47 +020011933 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011934 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
11935 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
11936 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
11937 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
11938 /* internal mic */
11939 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
11940 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
11941 /* ADC, choose mic */
11942 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11943 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
11944 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
11945 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
11946 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
11947 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
11948 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
11949 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
11950 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
11951 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(8)},
Tobin Davisf651b502007-10-26 12:40:47 +020011952 {}
11953};
11954
Tobin Davisf651b502007-10-26 12:40:47 +020011955/* mute/unmute internal speaker according to the hp jack and mute state */
11956static void alc262_ultra_automute(struct hda_codec *codec)
11957{
11958 struct alc_spec *spec = codec->spec;
11959 unsigned int mute;
Tobin Davisf651b502007-10-26 12:40:47 +020011960
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011961 mute = 0;
11962 /* auto-mute only when HP is used as HP */
11963 if (!spec->cur_mux[0]) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080011964 spec->jack_present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011965 if (spec->jack_present)
11966 mute = HDA_AMP_MUTE;
Tobin Davisf651b502007-10-26 12:40:47 +020011967 }
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011968 /* mute/unmute internal speaker */
11969 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
11970 HDA_AMP_MUTE, mute);
11971 /* mute/unmute HP */
11972 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
11973 HDA_AMP_MUTE, mute ? 0 : HDA_AMP_MUTE);
Tobin Davisf651b502007-10-26 12:40:47 +020011974}
11975
11976/* unsolicited event for HP jack sensing */
11977static void alc262_ultra_unsol_event(struct hda_codec *codec,
11978 unsigned int res)
11979{
11980 if ((res >> 26) != ALC880_HP_EVENT)
11981 return;
11982 alc262_ultra_automute(codec);
11983}
11984
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010011985static struct hda_input_mux alc262_ultra_capture_source = {
11986 .num_items = 2,
11987 .items = {
11988 { "Mic", 0x1 },
11989 { "Headphone", 0x7 },
11990 },
11991};
11992
11993static int alc262_ultra_mux_enum_put(struct snd_kcontrol *kcontrol,
11994 struct snd_ctl_elem_value *ucontrol)
11995{
11996 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
11997 struct alc_spec *spec = codec->spec;
11998 int ret;
11999
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012000 ret = alc_mux_enum_put(kcontrol, ucontrol);
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012001 if (!ret)
12002 return 0;
12003 /* reprogram the HP pin as mic or HP according to the input source */
12004 snd_hda_codec_write_cache(codec, 0x15, 0,
12005 AC_VERB_SET_PIN_WIDGET_CONTROL,
12006 spec->cur_mux[0] ? PIN_VREF80 : PIN_HP);
12007 alc262_ultra_automute(codec); /* mute/unmute HP */
12008 return ret;
12009}
12010
12011static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = {
12012 HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT),
12013 HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT),
12014 {
12015 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
12016 .name = "Capture Source",
Takashi Iwai54cbc9a2008-10-31 15:24:04 +010012017 .info = alc_mux_enum_info,
12018 .get = alc_mux_enum_get,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012019 .put = alc262_ultra_mux_enum_put,
12020 },
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +010012021 {
12022 .iface = NID_MAPPING,
12023 .name = "Capture Source",
12024 .private_value = 0x15,
12025 },
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012026 { } /* end */
12027};
12028
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012029/* We use two mixers depending on the output pin; 0x16 is a mono output
12030 * and thus it's bound with a different mixer.
12031 * This function returns which mixer amp should be used.
12032 */
12033static int alc262_check_volbit(hda_nid_t nid)
12034{
12035 if (!nid)
12036 return 0;
12037 else if (nid == 0x16)
12038 return 2;
12039 else
12040 return 1;
12041}
12042
12043static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012044 const char *pfx, int *vbits, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012045{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012046 unsigned long val;
12047 int vbit;
12048
12049 vbit = alc262_check_volbit(nid);
12050 if (!vbit)
12051 return 0;
12052 if (*vbits & vbit) /* a volume control for this mixer already there */
12053 return 0;
12054 *vbits |= vbit;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012055 if (vbit == 2)
12056 val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT);
12057 else
12058 val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012059 return __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012060}
12061
12062static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid,
Takashi Iwai033688a2010-09-08 15:47:09 +020012063 const char *pfx, int idx)
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012064{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012065 unsigned long val;
12066
12067 if (!nid)
12068 return 0;
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012069 if (nid == 0x16)
12070 val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT);
12071 else
12072 val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
Takashi Iwai033688a2010-09-08 15:47:09 +020012073 return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, idx, val);
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012074}
12075
Kailang Yangdf694da2005-12-05 19:42:22 +010012076/* add playback controls from the parsed DAC table */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012077static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
12078 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010012079{
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012080 const char *pfx;
12081 int vbits;
Takashi Iwai033688a2010-09-08 15:47:09 +020012082 int i, err;
Kailang Yangdf694da2005-12-05 19:42:22 +010012083
12084 spec->multiout.num_dacs = 1; /* only use one dac */
12085 spec->multiout.dac_nids = spec->private_dac_nids;
12086 spec->multiout.dac_nids[0] = 2;
12087
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012088 if (!cfg->speaker_pins[0] && !cfg->hp_pins[0])
12089 pfx = "Master";
12090 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
12091 pfx = "Speaker";
Takashi Iwai033688a2010-09-08 15:47:09 +020012092 else if (cfg->line_out_type == AUTO_PIN_HP_OUT)
12093 pfx = "Headphone";
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012094 else
12095 pfx = "Front";
Takashi Iwai033688a2010-09-08 15:47:09 +020012096 for (i = 0; i < 2; i++) {
12097 err = alc262_add_out_sw_ctl(spec, cfg->line_out_pins[i], pfx, i);
12098 if (err < 0)
12099 return err;
12100 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12101 err = alc262_add_out_sw_ctl(spec, cfg->speaker_pins[i],
12102 "Speaker", i);
12103 if (err < 0)
12104 return err;
12105 }
12106 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12107 err = alc262_add_out_sw_ctl(spec, cfg->hp_pins[i],
12108 "Headphone", i);
12109 if (err < 0)
12110 return err;
12111 }
12112 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012113
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012114 vbits = alc262_check_volbit(cfg->line_out_pins[0]) |
12115 alc262_check_volbit(cfg->speaker_pins[0]) |
12116 alc262_check_volbit(cfg->hp_pins[0]);
12117 if (vbits == 1 || vbits == 2)
12118 pfx = "Master"; /* only one mixer is used */
Takashi Iwaic3fc1f52009-08-25 16:08:47 +020012119 vbits = 0;
Takashi Iwai033688a2010-09-08 15:47:09 +020012120 for (i = 0; i < 2; i++) {
12121 err = alc262_add_out_vol_ctl(spec, cfg->line_out_pins[i], pfx,
12122 &vbits, i);
12123 if (err < 0)
12124 return err;
12125 if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
12126 err = alc262_add_out_vol_ctl(spec, cfg->speaker_pins[i],
12127 "Speaker", &vbits, i);
12128 if (err < 0)
12129 return err;
12130 }
12131 if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
12132 err = alc262_add_out_vol_ctl(spec, cfg->hp_pins[i],
12133 "Headphone", &vbits, i);
12134 if (err < 0)
12135 return err;
12136 }
12137 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012138 return 0;
Kailang Yangdf694da2005-12-05 19:42:22 +010012139}
12140
Takashi Iwai05f5f472009-08-25 13:10:18 +020012141#define alc262_auto_create_input_ctls \
Takashi Iwaieaa9b3a2010-01-17 13:09:33 +010012142 alc882_auto_create_input_ctls
Kailang Yangdf694da2005-12-05 19:42:22 +010012143
12144/*
12145 * generic initialization of ADC, input mixers and output mixers
12146 */
12147static struct hda_verb alc262_volume_init_verbs[] = {
12148 /*
12149 * Unmute ADC0-2 and set the default input to mic-in
12150 */
12151 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12152 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12153 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12154 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12155 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12156 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12157
Takashi Iwaicb53c622007-08-10 17:21:45 +020012158 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangdf694da2005-12-05 19:42:22 +010012159 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012160 * Note: PASD motherboards uses the Line In 2 as the input for
12161 * front panel mic (mic 2)
Kailang Yangdf694da2005-12-05 19:42:22 +010012162 */
12163 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012164 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12165 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12166 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12167 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12168 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Kailang Yangdf694da2005-12-05 19:42:22 +010012169
12170 /*
12171 * Set up output mixers (0x0c - 0x0f)
12172 */
12173 /* set vol=0 to output mixers */
12174 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12175 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12176 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yangea1fb292008-08-26 12:58:38 +020012177
Kailang Yangdf694da2005-12-05 19:42:22 +010012178 /* set up input amps for analog loopback */
12179 /* Amp Indices: DAC = 0, mixer = 1 */
12180 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12181 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12182 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12183 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12184 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12185 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12186
12187 /* FIXME: use matrix-type input source selection */
12188 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12189 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12190 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12191 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12192 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12193 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12194 /* Input mixer2 */
12195 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12196 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12197 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12198 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12199 /* Input mixer3 */
12200 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12201 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12202 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12203 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12204
12205 { }
12206};
12207
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012208static struct hda_verb alc262_HP_BPC_init_verbs[] = {
12209 /*
12210 * Unmute ADC0-2 and set the default input to mic-in
12211 */
12212 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12213 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12214 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12215 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12216 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12217 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12218
Takashi Iwaicb53c622007-08-10 17:21:45 +020012219 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012220 * mixer widget
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012221 * Note: PASD motherboards uses the Line In 2 as the input for
12222 * front panel mic (mic 2)
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012223 */
12224 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012225 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12226 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12227 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12228 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12229 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12230 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12231 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
Kailang Yangea1fb292008-08-26 12:58:38 +020012232
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012233 /*
12234 * Set up output mixers (0x0c - 0x0e)
12235 */
12236 /* set vol=0 to output mixers */
12237 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12238 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12239 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12240
12241 /* set up input amps for analog loopback */
12242 /* Amp Indices: DAC = 0, mixer = 1 */
12243 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12244 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12245 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12246 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12247 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12248 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12249
Takashi Iwaice875f02008-01-28 18:17:43 +010012250 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012251 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12252 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
12253
12254 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12255 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12256
12257 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12258 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12259
12260 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12261 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12262 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
12263 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12264 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
12265
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012266 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012267 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12268 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012269 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012270 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12271 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12272
12273
12274 /* FIXME: use matrix-type input source selection */
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012275 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */
12276 /* Input mixer1: only unmute Mic */
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012277 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012278 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12279 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12280 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12281 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12282 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12283 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12284 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12285 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012286 /* Input mixer2 */
12287 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012288 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12289 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12290 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12291 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12292 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12293 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12294 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12295 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012296 /* Input mixer3 */
12297 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
Jaroslav Kysela0e4835c2009-05-25 16:44:20 +020012298 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))},
12299 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))},
12300 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))},
12301 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))},
12302 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))},
12303 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))},
12304 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))},
12305 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))},
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012306
Takashi Iwaice875f02008-01-28 18:17:43 +010012307 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12308
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012309 { }
12310};
12311
Kailang Yangcd7509a2007-01-26 18:33:17 +010012312static struct hda_verb alc262_HP_BPC_WildWest_init_verbs[] = {
12313 /*
12314 * Unmute ADC0-2 and set the default input to mic-in
12315 */
12316 {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
12317 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12318 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
12319 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12320 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
12321 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12322
Takashi Iwaicb53c622007-08-10 17:21:45 +020012323 /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
Kailang Yangcd7509a2007-01-26 18:33:17 +010012324 * mixer widget
12325 * Note: PASD motherboards uses the Line In 2 as the input for front
12326 * panel mic (mic 2)
12327 */
12328 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020012329 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
12330 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
12331 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
12332 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
12333 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
12334 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
12335 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
12336 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
Kailang Yangcd7509a2007-01-26 18:33:17 +010012337 /*
12338 * Set up output mixers (0x0c - 0x0e)
12339 */
12340 /* set vol=0 to output mixers */
12341 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12342 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12343 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
12344
12345 /* set up input amps for analog loopback */
12346 /* Amp Indices: DAC = 0, mixer = 1 */
12347 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12348 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12349 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12350 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12351 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
12352 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
12353
12354
12355 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP */
12356 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Mono */
12357 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* rear MIC */
12358 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* Line in */
12359 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12360 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Line out */
12361 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD in */
12362
12363 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12364 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12365
12366 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
12367 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
12368
12369 /* {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, */
12370 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12371 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12372 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 },
12373 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12374 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 },
12375
12376 /* FIXME: use matrix-type input source selection */
12377 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
12378 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
12379 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, /*rear MIC*/
12380 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, /*Line in*/
12381 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, /*F MIC*/
12382 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, /*Front*/
12383 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, /*CD*/
12384 /* {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12385 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))}, /*HP*/
12386 /* Input mixer2 */
12387 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12388 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12389 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12390 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12391 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12392 /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12393 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12394 /* Input mixer3 */
12395 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
12396 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
12397 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
12398 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
12399 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))},
12400 /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x06 << 8))}, */
12401 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x07 << 8))},
12402
Takashi Iwaice875f02008-01-28 18:17:43 +010012403 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
12404
Kailang Yangcd7509a2007-01-26 18:33:17 +010012405 { }
12406};
12407
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012408static struct hda_verb alc262_toshiba_rx1_unsol_verbs[] = {
12409
12410 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Front Speaker */
12411 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
12412 {0x14, AC_VERB_SET_CONNECT_SEL, 0x01},
12413
12414 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* MIC jack */
12415 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Front MIC */
12416 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12417 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) },
12418
12419 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP jack */
12420 {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
12421 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
12422 {}
12423};
12424
Takashi Iwai18675e42010-09-08 15:55:44 +020012425/*
12426 * Pin config fixes
12427 */
12428enum {
12429 PINFIX_FSC_H270,
12430};
12431
12432static const struct alc_fixup alc262_fixups[] = {
12433 [PINFIX_FSC_H270] = {
12434 .pins = (const struct alc_pincfg[]) {
12435 { 0x14, 0x99130110 }, /* speaker */
12436 { 0x15, 0x0221142f }, /* front HP */
12437 { 0x1b, 0x0121141f }, /* rear HP */
12438 { }
12439 }
12440 },
12441 [PINFIX_PB_M5210] = {
12442 .verbs = (const struct hda_verb[]) {
12443 { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
12444 {}
12445 }
12446 },
12447};
12448
12449static struct snd_pci_quirk alc262_fixup_tbl[] = {
12450 SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", PINFIX_FSC_H270),
12451 {}
12452};
12453
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012454
Takashi Iwaicb53c622007-08-10 17:21:45 +020012455#ifdef CONFIG_SND_HDA_POWER_SAVE
12456#define alc262_loopbacks alc880_loopbacks
12457#endif
12458
Sasha Alexandrdef319f2009-06-16 16:00:15 -040012459/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012460#define alc262_pcm_analog_playback alc880_pcm_analog_playback
12461#define alc262_pcm_analog_capture alc880_pcm_analog_capture
12462#define alc262_pcm_digital_playback alc880_pcm_digital_playback
12463#define alc262_pcm_digital_capture alc880_pcm_digital_capture
12464
12465/*
12466 * BIOS auto configuration
12467 */
12468static int alc262_parse_auto_config(struct hda_codec *codec)
12469{
12470 struct alc_spec *spec = codec->spec;
12471 int err;
12472 static hda_nid_t alc262_ignore[] = { 0x1d, 0 };
12473
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012474 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
12475 alc262_ignore);
12476 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012477 return err;
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012478 if (!spec->autocfg.line_outs) {
Takashi Iwai0852d7a2009-02-11 11:35:15 +010012479 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012480 spec->multiout.max_channels = 2;
12481 spec->no_analog = 1;
12482 goto dig_only;
12483 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012484 return 0; /* can't find valid BIOS pin config */
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012485 }
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012486 err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg);
12487 if (err < 0)
12488 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020012489 err = alc262_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012490 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010012491 return err;
12492
12493 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
12494
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012495 dig_only:
Takashi Iwai757899a2010-07-30 10:48:14 +020012496 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012497
Takashi Iwai603c4012008-07-30 15:01:44 +020012498 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010012499 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010012500
Takashi Iwaid88897e2008-10-31 15:01:37 +010012501 add_verb(spec, alc262_volume_init_verbs);
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020012502 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020012503 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010012504
Takashi Iwai776e1842007-08-29 15:07:11 +020012505 err = alc_auto_add_mic_boost(codec);
12506 if (err < 0)
12507 return err;
12508
Kailang Yang6227cdc2010-02-25 08:36:52 +010012509 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020012510
Kailang Yangdf694da2005-12-05 19:42:22 +010012511 return 1;
12512}
12513
12514#define alc262_auto_init_multi_out alc882_auto_init_multi_out
12515#define alc262_auto_init_hp_out alc882_auto_init_hp_out
12516#define alc262_auto_init_analog_input alc882_auto_init_analog_input
Takashi Iwaif511b012008-08-15 16:46:42 +020012517#define alc262_auto_init_input_src alc882_auto_init_input_src
Kailang Yangdf694da2005-12-05 19:42:22 +010012518
12519
12520/* init callback for auto-configuration model -- overriding the default init */
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012521static void alc262_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010012522{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012523 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010012524 alc262_auto_init_multi_out(codec);
12525 alc262_auto_init_hp_out(codec);
12526 alc262_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020012527 alc262_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020012528 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010012529 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020012530 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012531}
12532
12533/*
12534 * configuration and preset
12535 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012536static const char *alc262_models[ALC262_MODEL_LAST] = {
12537 [ALC262_BASIC] = "basic",
12538 [ALC262_HIPPO] = "hippo",
12539 [ALC262_HIPPO_1] = "hippo_1",
12540 [ALC262_FUJITSU] = "fujitsu",
12541 [ALC262_HP_BPC] = "hp-bpc",
Kailang Yangcd7509a2007-01-26 18:33:17 +010012542 [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
Takashi Iwai61dc35d2007-11-14 12:26:44 +010012543 [ALC262_HP_TC_T5735] = "hp-tc-t5735",
Kailang Yang8c427222008-01-10 13:03:59 +010012544 [ALC262_HP_RP5700] = "hp-rp5700",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012545 [ALC262_BENQ_ED8] = "benq",
Takashi Iwai0f405022007-07-06 12:24:11 +020012546 [ALC262_BENQ_T31] = "benq-t31",
12547 [ALC262_SONY_ASSAMD] = "sony-assamd",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020012548 [ALC262_TOSHIBA_S06] = "toshiba-s06",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012549 [ALC262_TOSHIBA_RX1] = "toshiba-rx1",
Tobin Davisf651b502007-10-26 12:40:47 +020012550 [ALC262_ULTRA] = "ultra",
Jiang zhe0e31daf2008-03-20 12:12:39 +010012551 [ALC262_LENOVO_3000] = "lenovo-3000",
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012552 [ALC262_NEC] = "nec",
Tony Vroonba340e82009-02-02 19:01:30 +000012553 [ALC262_TYAN] = "tyan",
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012554 [ALC262_AUTO] = "auto",
12555};
12556
12557static struct snd_pci_quirk alc262_cfg_tbl[] = {
12558 SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012559 SND_PCI_QUIRK(0x1033, 0x8895, "NEC Versa S9100", ALC262_NEC),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012560 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1200, "HP xw series",
12561 ALC262_HP_BPC),
12562 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1300, "HP xw series",
12563 ALC262_HP_BPC),
Takashi Iwai53eff7e2009-02-27 17:49:44 +010012564 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x1700, "HP xw series",
12565 ALC262_HP_BPC),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012566 SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012567 SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012568 SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012569 SND_PCI_QUIRK(0x103c, 0x2803, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012570 SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012571 SND_PCI_QUIRK(0x103c, 0x2805, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012572 SND_PCI_QUIRK(0x103c, 0x2806, "HP D7000", ALC262_HP_BPC_D7000_WL),
Kailang Yangcd7509a2007-01-26 18:33:17 +010012573 SND_PCI_QUIRK(0x103c, 0x2807, "HP D7000", ALC262_HP_BPC_D7000_WF),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012574 SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
12575 SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
12576 SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012577 SND_PCI_QUIRK(0x103c, 0x302f, "HP Thin Client T5735",
12578 ALC262_HP_TC_T5735),
Kailang Yang8c427222008-01-10 13:03:59 +010012579 SND_PCI_QUIRK(0x103c, 0x2817, "HP RP5700", ALC262_HP_RP5700),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012580 SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012581 SND_PCI_QUIRK(0x104d, 0x8203, "Sony UX-90", ALC262_HIPPO),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012582 SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD),
Takashi Iwaibd6afe32009-03-04 11:30:25 +010012583 SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */
Takashi Iwai376b5082009-06-22 11:03:13 +020012584 SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06),
Daniel T Chen95491d92009-11-08 19:03:55 -050012585 SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO),
Takashi Iwai12929ba2009-11-17 15:58:35 +010012586 SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012587#if 0 /* disable the quirk since model=auto works better in recent versions */
Takashi Iwaif872a912009-02-26 00:57:01 +010012588 SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO",
12589 ALC262_SONY_ASSAMD),
Takashi Iwaic5b51652009-11-17 16:01:58 +010012590#endif
Akio Idehara36ca6e12008-06-09 22:57:40 +090012591 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012592 ALC262_TOSHIBA_RX1),
Kailang Yang80ffe862008-10-15 11:23:27 +020012593 SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012594 SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
Tony Vroon3f1eeae2008-02-25 16:44:13 +010012595 SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FUJITSU),
Tony Vroonba340e82009-02-02 19:01:30 +000012596 SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_TYAN),
Takashi Iwaidea0a502009-02-09 17:14:52 +010012597 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc032, "Samsung Q1",
12598 ALC262_ULTRA),
Luke Yelavich3e420e72008-12-16 12:37:47 +110012599 SND_PCI_QUIRK(0x144d, 0xc510, "Samsung Q45", ALC262_HIPPO),
Jiang zhe0e31daf2008-03-20 12:12:39 +010012600 SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000 y410", ALC262_LENOVO_3000),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012601 SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
Kailang Yang83c34212007-07-05 11:43:05 +020012602 SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010012603 SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
Kailang Yangdf694da2005-12-05 19:42:22 +010012604 {}
12605};
12606
12607static struct alc_config_preset alc262_presets[] = {
12608 [ALC262_BASIC] = {
12609 .mixers = { alc262_base_mixer },
12610 .init_verbs = { alc262_init_verbs },
12611 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12612 .dac_nids = alc262_dac_nids,
12613 .hp_nid = 0x03,
12614 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12615 .channel_mode = alc262_modes,
Takashi Iwaia3bcba32005-12-06 19:05:29 +010012616 .input_mux = &alc262_capture_source,
Kailang Yangdf694da2005-12-05 19:42:22 +010012617 },
Kailang Yangccc656c2006-10-17 12:32:26 +020012618 [ALC262_HIPPO] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020012619 .mixers = { alc262_hippo_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012620 .init_verbs = { alc262_init_verbs, alc_hp15_unsol_verbs},
Kailang Yangccc656c2006-10-17 12:32:26 +020012621 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12622 .dac_nids = alc262_dac_nids,
12623 .hp_nid = 0x03,
12624 .dig_out_nid = ALC262_DIGOUT_NID,
12625 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12626 .channel_mode = alc262_modes,
12627 .input_mux = &alc262_capture_source,
12628 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012629 .setup = alc262_hippo_setup,
12630 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012631 },
12632 [ALC262_HIPPO_1] = {
12633 .mixers = { alc262_hippo1_mixer },
12634 .init_verbs = { alc262_init_verbs, alc262_hippo1_unsol_verbs},
12635 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12636 .dac_nids = alc262_dac_nids,
12637 .hp_nid = 0x02,
12638 .dig_out_nid = ALC262_DIGOUT_NID,
12639 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12640 .channel_mode = alc262_modes,
12641 .input_mux = &alc262_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020012642 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012643 .setup = alc262_hippo1_setup,
12644 .init_hook = alc262_hippo_automute,
Kailang Yangccc656c2006-10-17 12:32:26 +020012645 },
Takashi Iwai834be882006-03-01 14:16:17 +010012646 [ALC262_FUJITSU] = {
12647 .mixers = { alc262_fujitsu_mixer },
Takashi Iwai39d3ed32007-10-12 15:03:48 +020012648 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
12649 alc262_fujitsu_unsol_verbs },
Takashi Iwai834be882006-03-01 14:16:17 +010012650 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12651 .dac_nids = alc262_dac_nids,
12652 .hp_nid = 0x03,
12653 .dig_out_nid = ALC262_DIGOUT_NID,
12654 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12655 .channel_mode = alc262_modes,
12656 .input_mux = &alc262_fujitsu_capture_source,
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012657 .unsol_event = alc262_fujitsu_unsol_event,
Takashi Iwaiebc7a402008-05-20 09:23:05 +020012658 .init_hook = alc262_fujitsu_init_hook,
Takashi Iwai834be882006-03-01 14:16:17 +010012659 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012660 [ALC262_HP_BPC] = {
12661 .mixers = { alc262_HP_BPC_mixer },
12662 .init_verbs = { alc262_HP_BPC_init_verbs },
12663 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12664 .dac_nids = alc262_dac_nids,
12665 .hp_nid = 0x03,
12666 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12667 .channel_mode = alc262_modes,
12668 .input_mux = &alc262_HP_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012669 .unsol_event = alc262_hp_bpc_unsol_event,
12670 .init_hook = alc262_hp_bpc_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012671 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012672 [ALC262_HP_BPC_D7000_WF] = {
12673 .mixers = { alc262_HP_BPC_WildWest_mixer },
12674 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12675 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12676 .dac_nids = alc262_dac_nids,
12677 .hp_nid = 0x03,
12678 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12679 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012680 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012681 .unsol_event = alc262_hp_wildwest_unsol_event,
12682 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012683 },
Kailang Yangcd7509a2007-01-26 18:33:17 +010012684 [ALC262_HP_BPC_D7000_WL] = {
12685 .mixers = { alc262_HP_BPC_WildWest_mixer,
12686 alc262_HP_BPC_WildWest_option_mixer },
12687 .init_verbs = { alc262_HP_BPC_WildWest_init_verbs },
12688 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12689 .dac_nids = alc262_dac_nids,
12690 .hp_nid = 0x03,
12691 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12692 .channel_mode = alc262_modes,
zhejiangaccbe492007-08-31 12:36:05 +020012693 .input_mux = &alc262_HP_D7000_capture_source,
Takashi Iwaice875f02008-01-28 18:17:43 +010012694 .unsol_event = alc262_hp_wildwest_unsol_event,
12695 .init_hook = alc262_hp_wildwest_automute,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012696 },
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012697 [ALC262_HP_TC_T5735] = {
12698 .mixers = { alc262_hp_t5735_mixer },
12699 .init_verbs = { alc262_init_verbs, alc262_hp_t5735_verbs },
12700 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12701 .dac_nids = alc262_dac_nids,
12702 .hp_nid = 0x03,
12703 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12704 .channel_mode = alc262_modes,
12705 .input_mux = &alc262_capture_source,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012706 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012707 .setup = alc262_hp_t5735_setup,
Takashi Iwaidc99be42010-01-20 08:35:06 +010012708 .init_hook = alc_inithook,
Kailang Yang8c427222008-01-10 13:03:59 +010012709 },
12710 [ALC262_HP_RP5700] = {
12711 .mixers = { alc262_hp_rp5700_mixer },
12712 .init_verbs = { alc262_init_verbs, alc262_hp_rp5700_verbs },
12713 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12714 .dac_nids = alc262_dac_nids,
12715 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12716 .channel_mode = alc262_modes,
12717 .input_mux = &alc262_hp_rp5700_capture_source,
Kailang Yang66d2a9d2007-11-14 12:06:21 +010012718 },
Takashi Iwai304dcaa2006-07-25 14:51:16 +020012719 [ALC262_BENQ_ED8] = {
12720 .mixers = { alc262_base_mixer },
12721 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs },
12722 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12723 .dac_nids = alc262_dac_nids,
12724 .hp_nid = 0x03,
12725 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12726 .channel_mode = alc262_modes,
12727 .input_mux = &alc262_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012728 },
Kailang Yang272a5272007-05-14 11:00:38 +020012729 [ALC262_SONY_ASSAMD] = {
12730 .mixers = { alc262_sony_mixer },
12731 .init_verbs = { alc262_init_verbs, alc262_sony_unsol_verbs},
12732 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12733 .dac_nids = alc262_dac_nids,
12734 .hp_nid = 0x02,
12735 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12736 .channel_mode = alc262_modes,
12737 .input_mux = &alc262_capture_source,
12738 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012739 .setup = alc262_hippo_setup,
12740 .init_hook = alc262_hippo_automute,
Kailang Yang83c34212007-07-05 11:43:05 +020012741 },
12742 [ALC262_BENQ_T31] = {
12743 .mixers = { alc262_benq_t31_mixer },
Wu Fengguang6732bd02009-07-30 09:19:14 +020012744 .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs,
12745 alc_hp15_unsol_verbs },
Kailang Yang83c34212007-07-05 11:43:05 +020012746 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12747 .dac_nids = alc262_dac_nids,
12748 .hp_nid = 0x03,
12749 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12750 .channel_mode = alc262_modes,
12751 .input_mux = &alc262_capture_source,
12752 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012753 .setup = alc262_hippo_setup,
12754 .init_hook = alc262_hippo_automute,
Kailang Yangea1fb292008-08-26 12:58:38 +020012755 },
Tobin Davisf651b502007-10-26 12:40:47 +020012756 [ALC262_ULTRA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010012757 .mixers = { alc262_ultra_mixer },
12758 .cap_mixer = alc262_ultra_capture_mixer,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012759 .init_verbs = { alc262_ultra_verbs },
Tobin Davisf651b502007-10-26 12:40:47 +020012760 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12761 .dac_nids = alc262_dac_nids,
Tobin Davisf651b502007-10-26 12:40:47 +020012762 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12763 .channel_mode = alc262_modes,
12764 .input_mux = &alc262_ultra_capture_source,
Takashi Iwaibb9f76c2008-03-12 12:51:09 +010012765 .adc_nids = alc262_adc_nids, /* ADC0 */
12766 .capsrc_nids = alc262_capsrc_nids,
12767 .num_adc_nids = 1, /* single ADC */
Tobin Davisf651b502007-10-26 12:40:47 +020012768 .unsol_event = alc262_ultra_unsol_event,
12769 .init_hook = alc262_ultra_automute,
12770 },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012771 [ALC262_LENOVO_3000] = {
12772 .mixers = { alc262_lenovo_3000_mixer },
12773 .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs,
Daniel T Chene2595322009-12-19 18:19:02 -050012774 alc262_lenovo_3000_unsol_verbs,
12775 alc262_lenovo_3000_init_verbs },
Jiang zhe0e31daf2008-03-20 12:12:39 +010012776 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12777 .dac_nids = alc262_dac_nids,
12778 .hp_nid = 0x03,
12779 .dig_out_nid = ALC262_DIGOUT_NID,
12780 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12781 .channel_mode = alc262_modes,
12782 .input_mux = &alc262_fujitsu_capture_source,
12783 .unsol_event = alc262_lenovo_3000_unsol_event,
12784 },
Pascal Terjane8f9ae22008-08-04 14:36:05 +020012785 [ALC262_NEC] = {
12786 .mixers = { alc262_nec_mixer },
12787 .init_verbs = { alc262_nec_verbs },
12788 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12789 .dac_nids = alc262_dac_nids,
12790 .hp_nid = 0x03,
12791 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12792 .channel_mode = alc262_modes,
12793 .input_mux = &alc262_capture_source,
12794 },
Kailang Yang4e555fe2008-08-26 13:05:55 +020012795 [ALC262_TOSHIBA_S06] = {
12796 .mixers = { alc262_toshiba_s06_mixer },
12797 .init_verbs = { alc262_init_verbs, alc262_toshiba_s06_verbs,
12798 alc262_eapd_verbs },
12799 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12800 .capsrc_nids = alc262_dmic_capsrc_nids,
12801 .dac_nids = alc262_dac_nids,
12802 .adc_nids = alc262_dmic_adc_nids, /* ADC0 */
Takashi Iwaiae14ef62009-06-22 08:16:56 +020012803 .num_adc_nids = 1, /* single ADC */
Kailang Yang4e555fe2008-08-26 13:05:55 +020012804 .dig_out_nid = ALC262_DIGOUT_NID,
12805 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12806 .channel_mode = alc262_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012807 .unsol_event = alc_sku_unsol_event,
12808 .setup = alc262_toshiba_s06_setup,
12809 .init_hook = alc_inithook,
Kailang Yang4e555fe2008-08-26 13:05:55 +020012810 },
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012811 [ALC262_TOSHIBA_RX1] = {
12812 .mixers = { alc262_toshiba_rx1_mixer },
12813 .init_verbs = { alc262_init_verbs, alc262_toshiba_rx1_unsol_verbs },
12814 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12815 .dac_nids = alc262_dac_nids,
12816 .hp_nid = 0x03,
12817 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12818 .channel_mode = alc262_modes,
12819 .input_mux = &alc262_capture_source,
12820 .unsol_event = alc262_hippo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012821 .setup = alc262_hippo_setup,
12822 .init_hook = alc262_hippo_automute,
Hiroshi Miura9f99a632008-08-28 16:09:06 +020012823 },
Tony Vroonba340e82009-02-02 19:01:30 +000012824 [ALC262_TYAN] = {
12825 .mixers = { alc262_tyan_mixer },
12826 .init_verbs = { alc262_init_verbs, alc262_tyan_verbs},
12827 .num_dacs = ARRAY_SIZE(alc262_dac_nids),
12828 .dac_nids = alc262_dac_nids,
12829 .hp_nid = 0x02,
12830 .dig_out_nid = ALC262_DIGOUT_NID,
12831 .num_channel_mode = ARRAY_SIZE(alc262_modes),
12832 .channel_mode = alc262_modes,
12833 .input_mux = &alc262_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020012834 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020012835 .setup = alc262_tyan_setup,
12836 .init_hook = alc_automute_amp,
Tony Vroonba340e82009-02-02 19:01:30 +000012837 },
Kailang Yangdf694da2005-12-05 19:42:22 +010012838};
12839
12840static int patch_alc262(struct hda_codec *codec)
12841{
12842 struct alc_spec *spec;
12843 int board_config;
12844 int err;
12845
Robert P. J. Daydc041e02006-12-19 14:44:15 +010012846 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010012847 if (spec == NULL)
12848 return -ENOMEM;
12849
12850 codec->spec = spec;
12851#if 0
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012852 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
12853 * under-run
12854 */
Kailang Yangdf694da2005-12-05 19:42:22 +010012855 {
12856 int tmp;
12857 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12858 tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
12859 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
12860 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
12861 }
12862#endif
Kailang Yangda00c242010-03-19 11:23:45 +010012863 alc_auto_parse_customize_define(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010012864
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020012865 alc_fix_pll_init(codec, 0x20, 0x0a, 10);
12866
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012867 board_config = snd_hda_check_board_config(codec, ALC262_MODEL_LAST,
12868 alc262_models,
12869 alc262_cfg_tbl);
Kailang Yangcd7509a2007-01-26 18:33:17 +010012870
Takashi Iwaif5fcc132006-11-24 17:07:44 +010012871 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020012872 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
12873 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010012874 board_config = ALC262_AUTO;
12875 }
12876
Takashi Iwai18675e42010-09-08 15:55:44 +020012877 if (board_config == ALC262_AUTO)
12878 alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1);
12879
Kailang Yangdf694da2005-12-05 19:42:22 +010012880 if (board_config == ALC262_AUTO) {
12881 /* automatic parse from the BIOS config */
12882 err = alc262_parse_auto_config(codec);
12883 if (err < 0) {
12884 alc_free(codec);
12885 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012886 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020012887 printk(KERN_INFO
12888 "hda_codec: Cannot set up configuration "
12889 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010012890 board_config = ALC262_BASIC;
12891 }
12892 }
12893
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012894 if (!spec->no_analog && has_cdefine_beep(codec)) {
Takashi Iwai07eba612009-02-19 08:06:35 +010012895 err = snd_hda_attach_beep_device(codec, 0x1);
12896 if (err < 0) {
12897 alc_free(codec);
12898 return err;
12899 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090012900 }
12901
Kailang Yangdf694da2005-12-05 19:42:22 +010012902 if (board_config != ALC262_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020012903 setup_preset(codec, &alc262_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010012904
Kailang Yangdf694da2005-12-05 19:42:22 +010012905 spec->stream_analog_playback = &alc262_pcm_analog_playback;
12906 spec->stream_analog_capture = &alc262_pcm_analog_capture;
Kailang Yangea1fb292008-08-26 12:58:38 +020012907
Kailang Yangdf694da2005-12-05 19:42:22 +010012908 spec->stream_digital_playback = &alc262_pcm_digital_playback;
12909 spec->stream_digital_capture = &alc262_pcm_digital_capture;
12910
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020012911 if (!spec->adc_nids && spec->input_mux) {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012912 int i;
12913 /* check whether the digital-mic has to be supported */
12914 for (i = 0; i < spec->input_mux->num_items; i++) {
12915 if (spec->input_mux->items[i].index >= 9)
12916 break;
12917 }
12918 if (i < spec->input_mux->num_items) {
12919 /* use only ADC0 */
12920 spec->adc_nids = alc262_dmic_adc_nids;
12921 spec->num_adc_nids = 1;
12922 spec->capsrc_nids = alc262_dmic_capsrc_nids;
Kailang Yangdf694da2005-12-05 19:42:22 +010012923 } else {
Takashi Iwai8c927b42009-06-22 10:56:54 +020012924 /* all analog inputs */
12925 /* check whether NID 0x07 is valid */
12926 unsigned int wcap = get_wcaps(codec, 0x07);
12927
12928 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020012929 wcap = get_wcaps_type(wcap);
Takashi Iwai8c927b42009-06-22 10:56:54 +020012930 if (wcap != AC_WID_AUD_IN) {
12931 spec->adc_nids = alc262_adc_nids_alt;
12932 spec->num_adc_nids =
12933 ARRAY_SIZE(alc262_adc_nids_alt);
12934 spec->capsrc_nids = alc262_capsrc_nids_alt;
12935 } else {
12936 spec->adc_nids = alc262_adc_nids;
12937 spec->num_adc_nids =
12938 ARRAY_SIZE(alc262_adc_nids);
12939 spec->capsrc_nids = alc262_capsrc_nids;
12940 }
Kailang Yangdf694da2005-12-05 19:42:22 +010012941 }
12942 }
Takashi Iwaie64f14f2009-01-20 18:32:55 +010012943 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020012944 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020012945 if (!spec->no_analog && has_cdefine_beep(codec))
Takashi Iwai07eba612009-02-19 08:06:35 +010012946 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Kailang Yangdf694da2005-12-05 19:42:22 +010012947
Takashi Iwai18675e42010-09-08 15:55:44 +020012948 if (board_config == ALC262_AUTO)
12949 alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0);
12950
Takashi Iwai2134ea42008-01-10 16:53:55 +010012951 spec->vmaster_nid = 0x0c;
12952
Kailang Yangdf694da2005-12-05 19:42:22 +010012953 codec->patch_ops = alc_patch_ops;
12954 if (board_config == ALC262_AUTO)
Takashi Iwaiae6b8132006-03-03 16:47:17 +010012955 spec->init_hook = alc262_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020012956
12957 alc_init_jacks(codec);
Takashi Iwaicb53c622007-08-10 17:21:45 +020012958#ifdef CONFIG_SND_HDA_POWER_SAVE
12959 if (!spec->loopback.amplist)
12960 spec->loopback.amplist = alc262_loopbacks;
12961#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020012962
Kailang Yangdf694da2005-12-05 19:42:22 +010012963 return 0;
12964}
12965
Kailang Yangdf694da2005-12-05 19:42:22 +010012966/*
Kailang Yanga361d842007-06-05 12:30:55 +020012967 * ALC268 channel source setting (2 channel)
12968 */
12969#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
12970#define alc268_modes alc260_modes
Kailang Yangea1fb292008-08-26 12:58:38 +020012971
Kailang Yanga361d842007-06-05 12:30:55 +020012972static hda_nid_t alc268_dac_nids[2] = {
12973 /* front, hp */
12974 0x02, 0x03
12975};
12976
12977static hda_nid_t alc268_adc_nids[2] = {
12978 /* ADC0-1 */
12979 0x08, 0x07
12980};
12981
12982static hda_nid_t alc268_adc_nids_alt[1] = {
12983 /* ADC0 */
12984 0x08
12985};
12986
Takashi Iwaie1406342008-02-11 18:32:32 +010012987static hda_nid_t alc268_capsrc_nids[2] = { 0x23, 0x24 };
12988
Kailang Yanga361d842007-06-05 12:30:55 +020012989static struct snd_kcontrol_new alc268_base_mixer[] = {
12990 /* output mixer control */
12991 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
12992 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
12993 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
12994 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010012995 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
12996 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
12997 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Kailang Yanga361d842007-06-05 12:30:55 +020012998 { }
12999};
13000
Takashi Iwai42171c12009-05-08 14:11:43 +020013001static struct snd_kcontrol_new alc268_toshiba_mixer[] = {
13002 /* output mixer control */
13003 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13004 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13005 ALC262_HIPPO_MASTER_SWITCH,
David Henningsson5f99f862011-01-04 15:24:24 +010013006 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13007 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
13008 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020013009 { }
13010};
13011
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013012/* bind Beep switches of both NID 0x0f and 0x10 */
13013static struct hda_bind_ctls alc268_bind_beep_sw = {
13014 .ops = &snd_hda_bind_sw,
13015 .values = {
13016 HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
13017 HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
13018 0
13019 },
13020};
13021
13022static struct snd_kcontrol_new alc268_beep_mixer[] = {
13023 HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
13024 HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
13025 { }
13026};
13027
Kailang Yangd1a991a2007-08-15 16:21:59 +020013028static struct hda_verb alc268_eapd_verbs[] = {
13029 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
13030 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
13031 { }
13032};
13033
Takashi Iwaid2738092007-08-16 14:59:45 +020013034/* Toshiba specific */
Takashi Iwaid2738092007-08-16 14:59:45 +020013035static struct hda_verb alc268_toshiba_verbs[] = {
13036 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13037 { } /* end */
13038};
13039
13040/* Acer specific */
Takashi Iwai889c4392007-08-23 18:56:52 +020013041/* bind volumes of both NID 0x02 and 0x03 */
Takashi Iwai6bc96852007-08-17 09:02:12 +020013042static struct hda_bind_ctls alc268_acer_bind_master_vol = {
13043 .ops = &snd_hda_bind_vol,
13044 .values = {
13045 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
13046 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
13047 0
13048 },
13049};
13050
Takashi Iwai889c4392007-08-23 18:56:52 +020013051/* mute/unmute internal speaker according to the hp jack and mute state */
13052static void alc268_acer_automute(struct hda_codec *codec, int force)
13053{
13054 struct alc_spec *spec = codec->spec;
13055 unsigned int mute;
13056
13057 if (force || !spec->sense_updated) {
Wu Fengguang864f92b2009-11-18 12:38:02 +080013058 spec->jack_present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai889c4392007-08-23 18:56:52 +020013059 spec->sense_updated = 1;
13060 }
13061 if (spec->jack_present)
13062 mute = HDA_AMP_MUTE; /* mute internal speaker */
13063 else /* unmute internal speaker if necessary */
13064 mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
13065 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
13066 HDA_AMP_MUTE, mute);
13067}
13068
13069
13070/* bind hp and internal speaker mute (with plug check) */
13071static int alc268_acer_master_sw_put(struct snd_kcontrol *kcontrol,
13072 struct snd_ctl_elem_value *ucontrol)
13073{
13074 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
13075 long *valp = ucontrol->value.integer.value;
13076 int change;
13077
Takashi Iwai8de56b72009-07-24 16:51:47 +020013078 change = amp_stereo_mute_update(codec, 0x14, HDA_OUTPUT, 0, valp);
Takashi Iwai889c4392007-08-23 18:56:52 +020013079 if (change)
13080 alc268_acer_automute(codec, 0);
13081 return change;
13082}
Takashi Iwaid2738092007-08-16 14:59:45 +020013083
Kailang Yang8ef355d2008-08-26 13:10:22 +020013084static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = {
13085 /* output mixer control */
13086 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13087 {
13088 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13089 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013090 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013091 .info = snd_hda_mixer_amp_switch_info,
13092 .get = snd_hda_mixer_amp_switch_get,
13093 .put = alc268_acer_master_sw_put,
13094 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13095 },
13096 HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x18, 0, HDA_INPUT),
13097 { }
13098};
13099
Takashi Iwaid2738092007-08-16 14:59:45 +020013100static struct snd_kcontrol_new alc268_acer_mixer[] = {
13101 /* output mixer control */
13102 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13103 {
13104 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13105 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013106 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaid2738092007-08-16 14:59:45 +020013107 .info = snd_hda_mixer_amp_switch_info,
13108 .get = snd_hda_mixer_amp_switch_get,
13109 .put = alc268_acer_master_sw_put,
13110 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13111 },
David Henningsson5f99f862011-01-04 15:24:24 +010013112 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13113 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
13114 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaid2738092007-08-16 14:59:45 +020013115 { }
13116};
13117
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013118static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = {
13119 /* output mixer control */
13120 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
13121 {
13122 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
13123 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010013124 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013125 .info = snd_hda_mixer_amp_switch_info,
13126 .get = snd_hda_mixer_amp_switch_get,
13127 .put = alc268_acer_master_sw_put,
13128 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
13129 },
David Henningsson5f99f862011-01-04 15:24:24 +010013130 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13131 HDA_CODEC_VOLUME("Line In Boost Volume", 0x1a, 0, HDA_INPUT),
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013132 { }
13133};
13134
Kailang Yang8ef355d2008-08-26 13:10:22 +020013135static struct hda_verb alc268_acer_aspire_one_verbs[] = {
13136 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
13137 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13138 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13139 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
13140 {0x23, AC_VERB_SET_CONNECT_SEL, 0x06},
13141 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, 0xa017},
13142 { }
13143};
13144
Takashi Iwaid2738092007-08-16 14:59:45 +020013145static struct hda_verb alc268_acer_verbs[] = {
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013146 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* internal dmic? */
13147 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaid2738092007-08-16 14:59:45 +020013148 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13149 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013150 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
13151 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwaid2738092007-08-16 14:59:45 +020013152 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13153 { }
13154};
13155
13156/* unsolicited event for HP jack sensing */
Takashi Iwai42171c12009-05-08 14:11:43 +020013157#define alc268_toshiba_unsol_event alc262_hippo_unsol_event
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013158#define alc268_toshiba_setup alc262_hippo_setup
13159#define alc268_toshiba_automute alc262_hippo_automute
Takashi Iwaid2738092007-08-16 14:59:45 +020013160
13161static void alc268_acer_unsol_event(struct hda_codec *codec,
13162 unsigned int res)
13163{
Takashi Iwai889c4392007-08-23 18:56:52 +020013164 if ((res >> 26) != ALC880_HP_EVENT)
Takashi Iwaid2738092007-08-16 14:59:45 +020013165 return;
13166 alc268_acer_automute(codec, 1);
13167}
13168
Takashi Iwai889c4392007-08-23 18:56:52 +020013169static void alc268_acer_init_hook(struct hda_codec *codec)
13170{
13171 alc268_acer_automute(codec, 1);
13172}
13173
Kailang Yang8ef355d2008-08-26 13:10:22 +020013174/* toggle speaker-output according to the hp-jack state */
13175static void alc268_aspire_one_speaker_automute(struct hda_codec *codec)
13176{
13177 unsigned int present;
13178 unsigned char bits;
13179
Wu Fengguang864f92b2009-11-18 12:38:02 +080013180 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013181 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013182 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013183 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013184 snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020013185 HDA_AMP_MUTE, bits);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013186}
13187
Kailang Yang8ef355d2008-08-26 13:10:22 +020013188static void alc268_acer_lc_unsol_event(struct hda_codec *codec,
13189 unsigned int res)
13190{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013191 switch (res >> 26) {
13192 case ALC880_HP_EVENT:
Kailang Yang8ef355d2008-08-26 13:10:22 +020013193 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013194 break;
13195 case ALC880_MIC_EVENT:
13196 alc_mic_automute(codec);
13197 break;
13198 }
13199}
13200
13201static void alc268_acer_lc_setup(struct hda_codec *codec)
13202{
13203 struct alc_spec *spec = codec->spec;
13204 spec->ext_mic.pin = 0x18;
13205 spec->ext_mic.mux_idx = 0;
13206 spec->int_mic.pin = 0x12;
13207 spec->int_mic.mux_idx = 6;
13208 spec->auto_mic = 1;
Kailang Yang8ef355d2008-08-26 13:10:22 +020013209}
13210
13211static void alc268_acer_lc_init_hook(struct hda_codec *codec)
13212{
13213 alc268_aspire_one_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013214 alc_mic_automute(codec);
Kailang Yang8ef355d2008-08-26 13:10:22 +020013215}
13216
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013217static struct snd_kcontrol_new alc268_dell_mixer[] = {
13218 /* output mixer control */
13219 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13220 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13221 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13222 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013223 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13224 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013225 { }
13226};
13227
13228static struct hda_verb alc268_dell_verbs[] = {
13229 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13230 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
13231 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013232 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013233 { }
13234};
13235
13236/* mute/unmute internal speaker according to the hp jack and mute state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013237static void alc268_dell_setup(struct hda_codec *codec)
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013238{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013239 struct alc_spec *spec = codec->spec;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013240
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013241 spec->autocfg.hp_pins[0] = 0x15;
13242 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013243 spec->ext_mic.pin = 0x18;
13244 spec->ext_mic.mux_idx = 0;
13245 spec->int_mic.pin = 0x19;
13246 spec->int_mic.mux_idx = 1;
13247 spec->auto_mic = 1;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013248}
13249
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013250static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = {
13251 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT),
13252 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
13253 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
13254 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
13255 HDA_CODEC_VOLUME("Mic Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13256 HDA_BIND_MUTE("Mic Capture Switch", 0x23, 2, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010013257 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
13258 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013259 { }
13260};
13261
13262static struct hda_verb alc267_quanta_il1_verbs[] = {
13263 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
13264 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
13265 { }
13266};
13267
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013268static void alc267_quanta_il1_setup(struct hda_codec *codec)
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013269{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013270 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013271 spec->autocfg.hp_pins[0] = 0x15;
13272 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013273 spec->ext_mic.pin = 0x18;
13274 spec->ext_mic.mux_idx = 0;
13275 spec->int_mic.pin = 0x19;
13276 spec->int_mic.mux_idx = 1;
13277 spec->auto_mic = 1;
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013278}
13279
Kailang Yanga361d842007-06-05 12:30:55 +020013280/*
13281 * generic initialization of ADC, input mixers and output mixers
13282 */
13283static struct hda_verb alc268_base_init_verbs[] = {
13284 /* Unmute DAC0-1 and set vol = 0 */
13285 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013286 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013287
13288 /*
13289 * Set up output mixers (0x0c - 0x0e)
13290 */
13291 /* set vol=0 to output mixers */
13292 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013293 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
13294
13295 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13296 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13297
13298 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13299 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
13300 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
13301 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13302 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13303 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13304 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13305 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13306
13307 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13308 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13309 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
13310 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013311 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013312
13313 /* set PCBEEP vol = 0, mute connections */
13314 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13315 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13316 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013317
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013318 /* Unmute Selector 23h,24h and set the default input to mic-in */
Kailang Yangea1fb292008-08-26 12:58:38 +020013319
Jiang Zhea9b3aa82007-12-20 13:13:13 +010013320 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
13321 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
13322 {0x24, AC_VERB_SET_CONNECT_SEL, 0x00},
13323 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013324
Kailang Yanga361d842007-06-05 12:30:55 +020013325 { }
13326};
13327
13328/*
13329 * generic initialization of ADC, input mixers and output mixers
13330 */
13331static struct hda_verb alc268_volume_init_verbs[] = {
13332 /* set output DAC */
Takashi Iwai4cfb91c2009-01-23 12:53:09 +010013333 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
13334 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Kailang Yanga361d842007-06-05 12:30:55 +020013335
13336 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13337 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
13338 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13339 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13340 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
13341
Kailang Yanga361d842007-06-05 12:30:55 +020013342 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yanga361d842007-06-05 12:30:55 +020013343 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13344 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13345
13346 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013347 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yanga361d842007-06-05 12:30:55 +020013348
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013349 /* set PCBEEP vol = 0, mute connections */
13350 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
13351 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
13352 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yanga361d842007-06-05 12:30:55 +020013353
13354 { }
13355};
13356
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013357static struct snd_kcontrol_new alc268_capture_nosrc_mixer[] = {
13358 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13359 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13360 { } /* end */
13361};
13362
Kailang Yanga361d842007-06-05 12:30:55 +020013363static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
13364 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13365 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013366 _DEFINE_CAPSRC(1),
Kailang Yanga361d842007-06-05 12:30:55 +020013367 { } /* end */
13368};
13369
13370static struct snd_kcontrol_new alc268_capture_mixer[] = {
13371 HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13372 HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
13373 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
13374 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013375 _DEFINE_CAPSRC(2),
Kailang Yanga361d842007-06-05 12:30:55 +020013376 { } /* end */
13377};
13378
13379static struct hda_input_mux alc268_capture_source = {
13380 .num_items = 4,
13381 .items = {
13382 { "Mic", 0x0 },
13383 { "Front Mic", 0x1 },
13384 { "Line", 0x2 },
13385 { "CD", 0x3 },
13386 },
13387};
13388
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013389static struct hda_input_mux alc268_acer_capture_source = {
13390 .num_items = 3,
13391 .items = {
13392 { "Mic", 0x0 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013393 { "Internal Mic", 0x1 },
13394 { "Line", 0x2 },
13395 },
13396};
13397
13398static struct hda_input_mux alc268_acer_dmic_capture_source = {
13399 .num_items = 3,
13400 .items = {
13401 { "Mic", 0x0 },
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013402 { "Internal Mic", 0x6 },
13403 { "Line", 0x2 },
13404 },
13405};
13406
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013407#ifdef CONFIG_SND_DEBUG
13408static struct snd_kcontrol_new alc268_test_mixer[] = {
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013409 /* Volume widgets */
13410 HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x02, 0x0, HDA_OUTPUT),
13411 HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x03, 0x0, HDA_OUTPUT),
13412 HDA_BIND_MUTE_MONO("Mono sum Playback Switch", 0x0e, 1, 2, HDA_INPUT),
13413 HDA_BIND_MUTE("LINE-OUT sum Playback Switch", 0x0f, 2, HDA_INPUT),
13414 HDA_BIND_MUTE("HP-OUT sum Playback Switch", 0x10, 2, HDA_INPUT),
13415 HDA_BIND_MUTE("LINE-OUT Playback Switch", 0x14, 2, HDA_OUTPUT),
13416 HDA_BIND_MUTE("HP-OUT Playback Switch", 0x15, 2, HDA_OUTPUT),
13417 HDA_BIND_MUTE("Mono Playback Switch", 0x16, 2, HDA_OUTPUT),
13418 HDA_CODEC_VOLUME("MIC1 Capture Volume", 0x18, 0x0, HDA_INPUT),
13419 HDA_BIND_MUTE("MIC1 Capture Switch", 0x18, 2, HDA_OUTPUT),
13420 HDA_CODEC_VOLUME("MIC2 Capture Volume", 0x19, 0x0, HDA_INPUT),
13421 HDA_CODEC_VOLUME("LINE1 Capture Volume", 0x1a, 0x0, HDA_INPUT),
13422 HDA_BIND_MUTE("LINE1 Capture Switch", 0x1a, 2, HDA_OUTPUT),
Takashi Iwaif0747ee2008-01-15 11:41:41 +010013423 /* The below appears problematic on some hardwares */
13424 /*HDA_CODEC_VOLUME("PCBEEP Playback Volume", 0x1d, 0x0, HDA_INPUT),*/
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013425 HDA_CODEC_VOLUME("PCM-IN1 Capture Volume", 0x23, 0x0, HDA_OUTPUT),
13426 HDA_BIND_MUTE("PCM-IN1 Capture Switch", 0x23, 2, HDA_OUTPUT),
13427 HDA_CODEC_VOLUME("PCM-IN2 Capture Volume", 0x24, 0x0, HDA_OUTPUT),
13428 HDA_BIND_MUTE("PCM-IN2 Capture Switch", 0x24, 2, HDA_OUTPUT),
13429
13430 /* Modes for retasking pin widgets */
13431 ALC_PIN_MODE("LINE-OUT pin mode", 0x14, ALC_PIN_DIR_INOUT),
13432 ALC_PIN_MODE("HP-OUT pin mode", 0x15, ALC_PIN_DIR_INOUT),
13433 ALC_PIN_MODE("MIC1 pin mode", 0x18, ALC_PIN_DIR_INOUT),
13434 ALC_PIN_MODE("LINE1 pin mode", 0x1a, ALC_PIN_DIR_INOUT),
13435
13436 /* Controls for GPIO pins, assuming they are configured as outputs */
13437 ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
13438 ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
13439 ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
13440 ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
13441
13442 /* Switches to allow the digital SPDIF output pin to be enabled.
13443 * The ALC268 does not have an SPDIF input.
13444 */
13445 ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x06, 0x01),
13446
13447 /* A switch allowing EAPD to be enabled. Some laptops seem to use
13448 * this output to turn on an external amplifier.
13449 */
13450 ALC_EAPD_CTRL_SWITCH("LINE-OUT EAPD Enable Switch", 0x0f, 0x02),
13451 ALC_EAPD_CTRL_SWITCH("HP-OUT EAPD Enable Switch", 0x10, 0x02),
13452
13453 { } /* end */
13454};
13455#endif
13456
Kailang Yanga361d842007-06-05 12:30:55 +020013457/* create input playback/capture controls for the given pin */
13458static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
13459 const char *ctlname, int idx)
13460{
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013461 hda_nid_t dac;
Kailang Yanga361d842007-06-05 12:30:55 +020013462 int err;
13463
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013464 switch (nid) {
13465 case 0x14:
13466 case 0x16:
13467 dac = 0x02;
13468 break;
13469 case 0x15:
Takashi Iwaib08b1632010-07-30 14:08:25 +020013470 case 0x1a: /* ALC259/269 only */
13471 case 0x1b: /* ALC259/269 only */
Kailang Yang531d8792010-04-09 10:57:33 +020013472 case 0x21: /* ALC269vb has this pin, too */
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013473 dac = 0x03;
13474 break;
13475 default:
Takashi Iwaic7a94342010-07-30 14:10:43 +020013476 snd_printd(KERN_WARNING "hda_codec: "
13477 "ignoring pin 0x%x as unknown\n", nid);
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013478 return 0;
13479 }
13480 if (spec->multiout.dac_nids[0] != dac &&
13481 spec->multiout.dac_nids[1] != dac) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013482 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013483 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
Kailang Yanga361d842007-06-05 12:30:55 +020013484 HDA_OUTPUT));
13485 if (err < 0)
13486 return err;
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013487 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
13488 }
13489
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013490 if (nid != 0x16)
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013491 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Kailang Yanga361d842007-06-05 12:30:55 +020013492 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013493 else /* mono */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013494 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013495 HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013496 if (err < 0)
13497 return err;
13498 return 0;
13499}
13500
13501/* add playback controls from the parsed DAC table */
13502static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
13503 const struct auto_pin_cfg *cfg)
13504{
13505 hda_nid_t nid;
13506 int err;
13507
Kailang Yanga361d842007-06-05 12:30:55 +020013508 spec->multiout.dac_nids = spec->private_dac_nids;
Kailang Yanga361d842007-06-05 12:30:55 +020013509
13510 nid = cfg->line_out_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013511 if (nid) {
13512 const char *name;
13513 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
13514 name = "Speaker";
13515 else
13516 name = "Front";
13517 err = alc268_new_analog_output(spec, nid, name, 0);
13518 if (err < 0)
13519 return err;
13520 }
Kailang Yanga361d842007-06-05 12:30:55 +020013521
13522 nid = cfg->speaker_pins[0];
13523 if (nid == 0x1d) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013524 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker",
Kailang Yanga361d842007-06-05 12:30:55 +020013525 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
13526 if (err < 0)
13527 return err;
David Henningsson7bfb9c02010-08-02 13:13:25 +020013528 } else if (nid) {
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013529 err = alc268_new_analog_output(spec, nid, "Speaker", 0);
13530 if (err < 0)
13531 return err;
Kailang Yanga361d842007-06-05 12:30:55 +020013532 }
13533 nid = cfg->hp_pins[0];
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013534 if (nid) {
13535 err = alc268_new_analog_output(spec, nid, "Headphone", 0);
13536 if (err < 0)
13537 return err;
13538 }
Kailang Yanga361d842007-06-05 12:30:55 +020013539
13540 nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
13541 if (nid == 0x16) {
Takashi Iwai0afe5f82009-10-02 09:20:00 +020013542 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono",
Takashi Iwai3f3b7c12009-07-17 14:36:59 +020013543 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT));
Kailang Yanga361d842007-06-05 12:30:55 +020013544 if (err < 0)
13545 return err;
13546 }
Kailang Yangea1fb292008-08-26 12:58:38 +020013547 return 0;
Kailang Yanga361d842007-06-05 12:30:55 +020013548}
13549
13550/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020013551static int alc268_auto_create_input_ctls(struct hda_codec *codec,
Kailang Yanga361d842007-06-05 12:30:55 +020013552 const struct auto_pin_cfg *cfg)
13553{
Takashi Iwai05f5f472009-08-25 13:10:18 +020013554 return alc_auto_create_input_ctls(codec, cfg, 0, 0x23, 0x24);
Kailang Yanga361d842007-06-05 12:30:55 +020013555}
13556
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013557static void alc268_auto_set_output_and_unmute(struct hda_codec *codec,
13558 hda_nid_t nid, int pin_type)
13559{
13560 int idx;
13561
13562 alc_set_pin_output(codec, nid, pin_type);
13563 if (nid == 0x14 || nid == 0x16)
13564 idx = 0;
13565 else
13566 idx = 1;
13567 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx);
13568}
13569
13570static void alc268_auto_init_multi_out(struct hda_codec *codec)
13571{
13572 struct alc_spec *spec = codec->spec;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013573 int i;
13574
13575 for (i = 0; i < spec->autocfg.line_outs; i++) {
13576 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013577 int pin_type = get_pin_type(spec->autocfg.line_out_type);
13578 alc268_auto_set_output_and_unmute(codec, nid, pin_type);
13579 }
13580}
13581
13582static void alc268_auto_init_hp_out(struct hda_codec *codec)
13583{
13584 struct alc_spec *spec = codec->spec;
13585 hda_nid_t pin;
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013586 int i;
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013587
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013588 for (i = 0; i < spec->autocfg.hp_outs; i++) {
13589 pin = spec->autocfg.hp_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013590 alc268_auto_set_output_and_unmute(codec, pin, PIN_HP);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013591 }
13592 for (i = 0; i < spec->autocfg.speaker_outs; i++) {
13593 pin = spec->autocfg.speaker_pins[i];
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013594 alc268_auto_set_output_and_unmute(codec, pin, PIN_OUT);
Takashi Iwaie1ca7b42010-09-20 14:58:57 +020013595 }
13596 if (spec->autocfg.mono_out_pin)
13597 snd_hda_codec_write(codec, spec->autocfg.mono_out_pin, 0,
13598 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013599}
13600
Kailang Yanga361d842007-06-05 12:30:55 +020013601static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
13602{
13603 struct alc_spec *spec = codec->spec;
13604 hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
13605 hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
13606 hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
13607 unsigned int dac_vol1, dac_vol2;
13608
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013609 if (line_nid == 0x1d || speaker_nid == 0x1d) {
Kailang Yanga361d842007-06-05 12:30:55 +020013610 snd_hda_codec_write(codec, speaker_nid, 0,
13611 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013612 /* mute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013613 snd_hda_codec_write(codec, 0x0f, 0,
13614 AC_VERB_SET_AMP_GAIN_MUTE,
13615 AMP_IN_UNMUTE(1));
13616 snd_hda_codec_write(codec, 0x10, 0,
13617 AC_VERB_SET_AMP_GAIN_MUTE,
13618 AMP_IN_UNMUTE(1));
13619 } else {
Takashi Iwaie9af4f32009-08-29 23:23:08 +020013620 /* unmute mixer inputs from 0x1d */
Kailang Yanga361d842007-06-05 12:30:55 +020013621 snd_hda_codec_write(codec, 0x0f, 0,
13622 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13623 snd_hda_codec_write(codec, 0x10, 0,
13624 AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
13625 }
13626
13627 dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
Kailang Yangea1fb292008-08-26 12:58:38 +020013628 if (line_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013629 dac_vol2 = AMP_OUT_ZERO;
13630 else if (line_nid == 0x15)
13631 dac_vol1 = AMP_OUT_ZERO;
Kailang Yangea1fb292008-08-26 12:58:38 +020013632 if (hp_nid == 0x14)
Kailang Yanga361d842007-06-05 12:30:55 +020013633 dac_vol2 = AMP_OUT_ZERO;
13634 else if (hp_nid == 0x15)
13635 dac_vol1 = AMP_OUT_ZERO;
13636 if (line_nid != 0x16 || hp_nid != 0x16 ||
13637 spec->autocfg.line_out_pins[1] != 0x16 ||
13638 spec->autocfg.line_out_pins[2] != 0x16)
13639 dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
13640
13641 snd_hda_codec_write(codec, 0x02, 0,
13642 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
13643 snd_hda_codec_write(codec, 0x03, 0,
13644 AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
13645}
13646
Sasha Alexandrdef319f2009-06-16 16:00:15 -040013647/* pcm configuration: identical with ALC880 */
Kailang Yanga361d842007-06-05 12:30:55 +020013648#define alc268_pcm_analog_playback alc880_pcm_analog_playback
13649#define alc268_pcm_analog_capture alc880_pcm_analog_capture
Takashi Iwai63300792008-01-24 15:31:36 +010013650#define alc268_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
Kailang Yanga361d842007-06-05 12:30:55 +020013651#define alc268_pcm_digital_playback alc880_pcm_digital_playback
13652
13653/*
13654 * BIOS auto configuration
13655 */
13656static int alc268_parse_auto_config(struct hda_codec *codec)
13657{
13658 struct alc_spec *spec = codec->spec;
13659 int err;
13660 static hda_nid_t alc268_ignore[] = { 0 };
13661
13662 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
13663 alc268_ignore);
13664 if (err < 0)
13665 return err;
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013666 if (!spec->autocfg.line_outs) {
13667 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
13668 spec->multiout.max_channels = 2;
13669 spec->no_analog = 1;
13670 goto dig_only;
13671 }
Kailang Yanga361d842007-06-05 12:30:55 +020013672 return 0; /* can't find valid BIOS pin config */
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013673 }
Kailang Yanga361d842007-06-05 12:30:55 +020013674 err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
13675 if (err < 0)
13676 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020013677 err = alc268_auto_create_input_ctls(codec, &spec->autocfg);
Kailang Yanga361d842007-06-05 12:30:55 +020013678 if (err < 0)
13679 return err;
13680
13681 spec->multiout.max_channels = 2;
13682
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013683 dig_only:
Kailang Yanga361d842007-06-05 12:30:55 +020013684 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020013685 alc_auto_parse_digital(codec);
Takashi Iwai603c4012008-07-30 15:01:44 +020013686 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013687 add_mixer(spec, spec->kctls.list);
Kailang Yanga361d842007-06-05 12:30:55 +020013688
Takashi Iwai892981f2009-03-02 08:04:35 +010013689 if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d)
Takashi Iwaid88897e2008-10-31 15:01:37 +010013690 add_mixer(spec, alc268_beep_mixer);
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013691
Takashi Iwaid88897e2008-10-31 15:01:37 +010013692 add_verb(spec, alc268_volume_init_verbs);
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030013693 spec->num_mux_defs = 2;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020013694 spec->input_mux = &spec->private_imux[0];
Kailang Yanga361d842007-06-05 12:30:55 +020013695
Takashi Iwai776e1842007-08-29 15:07:11 +020013696 err = alc_auto_add_mic_boost(codec);
13697 if (err < 0)
13698 return err;
13699
Kailang Yang6227cdc2010-02-25 08:36:52 +010013700 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai1d955eb2009-06-29 11:33:53 +020013701
Kailang Yanga361d842007-06-05 12:30:55 +020013702 return 1;
13703}
13704
Kailang Yanga361d842007-06-05 12:30:55 +020013705#define alc268_auto_init_analog_input alc882_auto_init_analog_input
13706
13707/* init callback for auto-configuration model -- overriding the default init */
13708static void alc268_auto_init(struct hda_codec *codec)
13709{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013710 struct alc_spec *spec = codec->spec;
Kailang Yanga361d842007-06-05 12:30:55 +020013711 alc268_auto_init_multi_out(codec);
13712 alc268_auto_init_hp_out(codec);
13713 alc268_auto_init_mono_speaker_out(codec);
13714 alc268_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020013715 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010013716 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020013717 alc_inithook(codec);
Kailang Yanga361d842007-06-05 12:30:55 +020013718}
13719
13720/*
13721 * configuration and preset
13722 */
13723static const char *alc268_models[ALC268_MODEL_LAST] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013724 [ALC267_QUANTA_IL1] = "quanta-il1",
Kailang Yanga361d842007-06-05 12:30:55 +020013725 [ALC268_3ST] = "3stack",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020013726 [ALC268_TOSHIBA] = "toshiba",
Takashi Iwaid2738092007-08-16 14:59:45 +020013727 [ALC268_ACER] = "acer",
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013728 [ALC268_ACER_DMIC] = "acer-dmic",
Kailang Yang8ef355d2008-08-26 13:10:22 +020013729 [ALC268_ACER_ASPIRE_ONE] = "acer-aspire",
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013730 [ALC268_DELL] = "dell",
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013731 [ALC268_ZEPTO] = "zepto",
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013732#ifdef CONFIG_SND_DEBUG
13733 [ALC268_TEST] = "test",
13734#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013735 [ALC268_AUTO] = "auto",
13736};
13737
13738static struct snd_pci_quirk alc268_cfg_tbl[] = {
Takashi Iwaia0b8f7d2008-04-22 19:39:49 +020013739 SND_PCI_QUIRK(0x1025, 0x011e, "Acer Aspire 5720z", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013740 SND_PCI_QUIRK(0x1025, 0x0126, "Acer", ALC268_ACER),
Andy Shevchenkodafc8352008-01-25 11:53:50 +010013741 SND_PCI_QUIRK(0x1025, 0x012e, "Acer Aspire 5310", ALC268_ACER),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010013742 SND_PCI_QUIRK(0x1025, 0x0130, "Acer Extensa 5210", ALC268_ACER),
Andy Shevchenko29a52c22008-01-24 17:29:00 +010013743 SND_PCI_QUIRK(0x1025, 0x0136, "Acer Aspire 5315", ALC268_ACER),
Kailang Yang8ef355d2008-08-26 13:10:22 +020013744 SND_PCI_QUIRK(0x1025, 0x015b, "Acer Aspire One",
13745 ALC268_ACER_ASPIRE_ONE),
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013746 SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL),
Daniel T Chena1bf8082009-11-01 18:32:29 -050013747 SND_PCI_QUIRK_MASK(0x1028, 0xfff0, 0x02b0,
13748 "Dell Inspiron Mini9/Vostro A90", ALC268_DELL),
Takashi Iwai33d78672009-09-08 11:03:41 +020013749 /* almost compatible with toshiba but with optional digital outs;
13750 * auto-probing seems working fine
13751 */
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013752 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series",
Takashi Iwai33d78672009-09-08 11:03:41 +020013753 ALC268_AUTO),
Kailang Yanga361d842007-06-05 12:30:55 +020013754 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
Takashi Iwai8871e5b2009-06-02 01:02:50 +020013755 SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO),
Tony Vroon378bd6a2008-06-04 12:08:30 +020013756 SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA),
Takashi Iwaib875bf32007-09-06 15:00:27 +020013757 SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER),
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013758 SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1),
Kailang Yanga361d842007-06-05 12:30:55 +020013759 {}
13760};
13761
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013762/* Toshiba laptops have no unique PCI SSID but only codec SSID */
13763static struct snd_pci_quirk alc268_ssid_cfg_tbl[] = {
13764 SND_PCI_QUIRK(0x1179, 0xff0a, "TOSHIBA X-200", ALC268_AUTO),
13765 SND_PCI_QUIRK(0x1179, 0xff0e, "TOSHIBA X-200 HDMI", ALC268_AUTO),
13766 SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05",
13767 ALC268_TOSHIBA),
13768 {}
13769};
13770
Kailang Yanga361d842007-06-05 12:30:55 +020013771static struct alc_config_preset alc268_presets[] = {
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013772 [ALC267_QUANTA_IL1] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013773 .mixers = { alc267_quanta_il1_mixer, alc268_beep_mixer,
13774 alc268_capture_nosrc_mixer },
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013775 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13776 alc267_quanta_il1_verbs },
13777 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13778 .dac_nids = alc268_dac_nids,
13779 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13780 .adc_nids = alc268_adc_nids_alt,
13781 .hp_nid = 0x03,
13782 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13783 .channel_mode = alc268_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013784 .unsol_event = alc_sku_unsol_event,
13785 .setup = alc267_quanta_il1_setup,
13786 .init_hook = alc_inithook,
Herton Ronaldo Krzesinskieb5a6622008-04-14 13:46:28 +020013787 },
Kailang Yanga361d842007-06-05 12:30:55 +020013788 [ALC268_3ST] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013789 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13790 alc268_beep_mixer },
Kailang Yanga361d842007-06-05 12:30:55 +020013791 .init_verbs = { alc268_base_init_verbs },
13792 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13793 .dac_nids = alc268_dac_nids,
13794 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13795 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013796 .capsrc_nids = alc268_capsrc_nids,
Kailang Yanga361d842007-06-05 12:30:55 +020013797 .hp_nid = 0x03,
13798 .dig_out_nid = ALC268_DIGOUT_NID,
13799 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13800 .channel_mode = alc268_modes,
13801 .input_mux = &alc268_capture_source,
13802 },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013803 [ALC268_TOSHIBA] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020013804 .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013805 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013806 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13807 alc268_toshiba_verbs },
Kailang Yangd1a991a2007-08-15 16:21:59 +020013808 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13809 .dac_nids = alc268_dac_nids,
13810 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13811 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013812 .capsrc_nids = alc268_capsrc_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013813 .hp_nid = 0x03,
13814 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13815 .channel_mode = alc268_modes,
13816 .input_mux = &alc268_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013817 .unsol_event = alc268_toshiba_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013818 .setup = alc268_toshiba_setup,
13819 .init_hook = alc268_toshiba_automute,
Takashi Iwaid2738092007-08-16 14:59:45 +020013820 },
13821 [ALC268_ACER] = {
Takashi Iwai432fd132009-09-30 08:13:44 +020013822 .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013823 alc268_beep_mixer },
Takashi Iwaid2738092007-08-16 14:59:45 +020013824 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13825 alc268_acer_verbs },
13826 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13827 .dac_nids = alc268_dac_nids,
13828 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13829 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013830 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwaid2738092007-08-16 14:59:45 +020013831 .hp_nid = 0x02,
13832 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13833 .channel_mode = alc268_modes,
Takashi Iwai0ccb5412008-03-06 16:58:35 +010013834 .input_mux = &alc268_acer_capture_source,
Takashi Iwaid2738092007-08-16 14:59:45 +020013835 .unsol_event = alc268_acer_unsol_event,
Takashi Iwai889c4392007-08-23 18:56:52 +020013836 .init_hook = alc268_acer_init_hook,
Kailang Yangd1a991a2007-08-15 16:21:59 +020013837 },
Takashi Iwaic238b4f2008-11-05 14:57:20 +010013838 [ALC268_ACER_DMIC] = {
13839 .mixers = { alc268_acer_dmic_mixer, alc268_capture_alt_mixer,
13840 alc268_beep_mixer },
13841 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13842 alc268_acer_verbs },
13843 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13844 .dac_nids = alc268_dac_nids,
13845 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13846 .adc_nids = alc268_adc_nids_alt,
13847 .capsrc_nids = alc268_capsrc_nids,
13848 .hp_nid = 0x02,
13849 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13850 .channel_mode = alc268_modes,
13851 .input_mux = &alc268_acer_dmic_capture_source,
13852 .unsol_event = alc268_acer_unsol_event,
13853 .init_hook = alc268_acer_init_hook,
13854 },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013855 [ALC268_ACER_ASPIRE_ONE] = {
13856 .mixers = { alc268_acer_aspire_one_mixer,
Takashi Iwai22971e32009-02-10 11:56:44 +010013857 alc268_beep_mixer,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013858 alc268_capture_nosrc_mixer },
Kailang Yang8ef355d2008-08-26 13:10:22 +020013859 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13860 alc268_acer_aspire_one_verbs },
13861 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13862 .dac_nids = alc268_dac_nids,
13863 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13864 .adc_nids = alc268_adc_nids_alt,
13865 .capsrc_nids = alc268_capsrc_nids,
13866 .hp_nid = 0x03,
13867 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13868 .channel_mode = alc268_modes,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013869 .unsol_event = alc268_acer_lc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013870 .setup = alc268_acer_lc_setup,
Kailang Yang8ef355d2008-08-26 13:10:22 +020013871 .init_hook = alc268_acer_lc_init_hook,
13872 },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013873 [ALC268_DELL] = {
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013874 .mixers = { alc268_dell_mixer, alc268_beep_mixer,
13875 alc268_capture_nosrc_mixer },
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013876 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13877 alc268_dell_verbs },
13878 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13879 .dac_nids = alc268_dac_nids,
Takashi Iwaifdbc6622009-08-19 00:18:10 +020013880 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13881 .adc_nids = alc268_adc_nids_alt,
13882 .capsrc_nids = alc268_capsrc_nids,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013883 .hp_nid = 0x02,
13884 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13885 .channel_mode = alc268_modes,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020013886 .unsol_event = alc_sku_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013887 .setup = alc268_dell_setup,
13888 .init_hook = alc_inithook,
Takashi Iwai3866f0b2008-01-15 12:37:42 +010013889 },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013890 [ALC268_ZEPTO] = {
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013891 .mixers = { alc268_base_mixer, alc268_capture_alt_mixer,
13892 alc268_beep_mixer },
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013893 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13894 alc268_toshiba_verbs },
13895 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13896 .dac_nids = alc268_dac_nids,
13897 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13898 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013899 .capsrc_nids = alc268_capsrc_nids,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013900 .hp_nid = 0x03,
13901 .dig_out_nid = ALC268_DIGOUT_NID,
13902 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13903 .channel_mode = alc268_modes,
13904 .input_mux = &alc268_capture_source,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020013905 .setup = alc268_toshiba_setup,
13906 .init_hook = alc268_toshiba_automute,
Mirco Tischlerf12462c2008-02-04 12:33:59 +010013907 },
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013908#ifdef CONFIG_SND_DEBUG
13909 [ALC268_TEST] = {
13910 .mixers = { alc268_test_mixer, alc268_capture_mixer },
13911 .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs,
13912 alc268_volume_init_verbs },
13913 .num_dacs = ARRAY_SIZE(alc268_dac_nids),
13914 .dac_nids = alc268_dac_nids,
13915 .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
13916 .adc_nids = alc268_adc_nids_alt,
Takashi Iwaie1406342008-02-11 18:32:32 +010013917 .capsrc_nids = alc268_capsrc_nids,
Jonathan Woithe86c53bd2008-01-08 12:33:19 +010013918 .hp_nid = 0x03,
13919 .dig_out_nid = ALC268_DIGOUT_NID,
13920 .num_channel_mode = ARRAY_SIZE(alc268_modes),
13921 .channel_mode = alc268_modes,
13922 .input_mux = &alc268_capture_source,
13923 },
13924#endif
Kailang Yanga361d842007-06-05 12:30:55 +020013925};
13926
13927static int patch_alc268(struct hda_codec *codec)
13928{
13929 struct alc_spec *spec;
13930 int board_config;
Takashi Iwai22971e32009-02-10 11:56:44 +010013931 int i, has_beep, err;
Kailang Yanga361d842007-06-05 12:30:55 +020013932
Julia Lawallef86f582009-12-19 08:18:03 +010013933 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yanga361d842007-06-05 12:30:55 +020013934 if (spec == NULL)
13935 return -ENOMEM;
13936
13937 codec->spec = spec;
13938
13939 board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
13940 alc268_models,
13941 alc268_cfg_tbl);
13942
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013943 if (board_config < 0 || board_config >= ALC268_MODEL_LAST)
13944 board_config = snd_hda_check_board_codec_sid_config(codec,
Takashi Iwai50ae0aa2010-03-08 12:09:59 +010013945 ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl);
Takashi Iwai3abf2f32009-08-19 20:05:02 +020013946
Kailang Yanga361d842007-06-05 12:30:55 +020013947 if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020013948 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
13949 codec->chip_name);
Kailang Yanga361d842007-06-05 12:30:55 +020013950 board_config = ALC268_AUTO;
13951 }
13952
13953 if (board_config == ALC268_AUTO) {
13954 /* automatic parse from the BIOS config */
13955 err = alc268_parse_auto_config(codec);
13956 if (err < 0) {
13957 alc_free(codec);
13958 return err;
13959 } else if (!err) {
13960 printk(KERN_INFO
13961 "hda_codec: Cannot set up configuration "
13962 "from BIOS. Using base mode...\n");
13963 board_config = ALC268_3ST;
13964 }
13965 }
13966
13967 if (board_config != ALC268_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020013968 setup_preset(codec, &alc268_presets[board_config]);
Kailang Yanga361d842007-06-05 12:30:55 +020013969
Kailang Yanga361d842007-06-05 12:30:55 +020013970 spec->stream_analog_playback = &alc268_pcm_analog_playback;
13971 spec->stream_analog_capture = &alc268_pcm_analog_capture;
Takashi Iwai63300792008-01-24 15:31:36 +010013972 spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture;
Kailang Yanga361d842007-06-05 12:30:55 +020013973
Kailang Yanga361d842007-06-05 12:30:55 +020013974 spec->stream_digital_playback = &alc268_pcm_digital_playback;
13975
Takashi Iwai22971e32009-02-10 11:56:44 +010013976 has_beep = 0;
13977 for (i = 0; i < spec->num_mixers; i++) {
13978 if (spec->mixers[i] == alc268_beep_mixer) {
13979 has_beep = 1;
13980 break;
13981 }
13982 }
13983
13984 if (has_beep) {
13985 err = snd_hda_attach_beep_device(codec, 0x1);
13986 if (err < 0) {
13987 alc_free(codec);
13988 return err;
13989 }
13990 if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
13991 /* override the amp caps for beep generator */
13992 snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013993 (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
13994 (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
13995 (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
13996 (0 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai22971e32009-02-10 11:56:44 +010013997 }
Takashi Iwaiaef9d312008-02-19 13:16:41 +010013998
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010013999 if (!spec->no_analog && !spec->adc_nids && spec->input_mux) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014000 /* check whether NID 0x07 is valid */
14001 unsigned int wcap = get_wcaps(codec, 0x07);
Takashi Iwai85860c02008-02-19 15:00:15 +010014002 int i;
Kailang Yanga361d842007-06-05 12:30:55 +020014003
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014004 spec->capsrc_nids = alc268_capsrc_nids;
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014005 /* get type */
Takashi Iwaia22d5432009-07-27 12:54:26 +020014006 wcap = get_wcaps_type(wcap);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014007 if (spec->auto_mic ||
14008 wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014009 spec->adc_nids = alc268_adc_nids_alt;
14010 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
Takashi Iwaidefb5ab2009-10-07 15:12:27 +020014011 if (spec->auto_mic)
14012 fixup_automic_adc(codec);
Takashi Iwaifdbc6622009-08-19 00:18:10 +020014013 if (spec->auto_mic || spec->input_mux->num_items == 1)
14014 add_mixer(spec, alc268_capture_nosrc_mixer);
14015 else
14016 add_mixer(spec, alc268_capture_alt_mixer);
Takashi Iwai3866f0b2008-01-15 12:37:42 +010014017 } else {
14018 spec->adc_nids = alc268_adc_nids;
14019 spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
Takashi Iwaid88897e2008-10-31 15:01:37 +010014020 add_mixer(spec, alc268_capture_mixer);
Kailang Yanga361d842007-06-05 12:30:55 +020014021 }
Takashi Iwai85860c02008-02-19 15:00:15 +010014022 /* set default input source */
14023 for (i = 0; i < spec->num_adc_nids; i++)
14024 snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
14025 0, AC_VERB_SET_CONNECT_SEL,
Herton Ronaldo Krzesinski59085892009-08-11 22:33:09 -030014026 i < spec->num_mux_defs ?
14027 spec->input_mux[i].items[0].index :
Takashi Iwai85860c02008-02-19 15:00:15 +010014028 spec->input_mux->items[0].index);
Kailang Yanga361d842007-06-05 12:30:55 +020014029 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010014030
14031 spec->vmaster_nid = 0x02;
14032
Kailang Yanga361d842007-06-05 12:30:55 +020014033 codec->patch_ops = alc_patch_ops;
14034 if (board_config == ALC268_AUTO)
14035 spec->init_hook = alc268_auto_init;
Kailang Yangea1fb292008-08-26 12:58:38 +020014036
Kailang Yangbf1b0222010-10-21 08:49:56 +020014037 alc_init_jacks(codec);
14038
Kailang Yanga361d842007-06-05 12:30:55 +020014039 return 0;
14040}
14041
14042/*
Kailang Yangf6a92242007-12-13 16:52:54 +010014043 * ALC269 channel source setting (2 channel)
14044 */
14045#define ALC269_DIGOUT_NID ALC880_DIGOUT_NID
14046
14047#define alc269_dac_nids alc260_dac_nids
14048
14049static hda_nid_t alc269_adc_nids[1] = {
14050 /* ADC1 */
Kailang Yangf53281e2008-07-18 12:36:43 +020014051 0x08,
14052};
14053
Takashi Iwaie01bf502008-08-21 16:25:07 +020014054static hda_nid_t alc269_capsrc_nids[1] = {
14055 0x23,
14056};
14057
Kailang Yang84898e82010-02-04 14:16:14 +010014058static hda_nid_t alc269vb_adc_nids[1] = {
14059 /* ADC1 */
14060 0x09,
14061};
14062
14063static hda_nid_t alc269vb_capsrc_nids[1] = {
14064 0x22,
14065};
14066
Takashi Iwai66946352010-03-29 17:21:45 +020014067static hda_nid_t alc269_adc_candidates[] = {
14068 0x08, 0x09, 0x07,
14069};
Takashi Iwaie01bf502008-08-21 16:25:07 +020014070
Kailang Yangf6a92242007-12-13 16:52:54 +010014071#define alc269_modes alc260_modes
14072#define alc269_capture_source alc880_lg_lw_capture_source
14073
14074static struct snd_kcontrol_new alc269_base_mixer[] = {
14075 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14076 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14077 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
14078 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
14079 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14080 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014081 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014082 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14083 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014084 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangf6a92242007-12-13 16:52:54 +010014085 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
14086 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
14087 { } /* end */
14088};
14089
Kailang Yang60db6b52008-08-26 13:13:00 +020014090static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = {
14091 /* output mixer control */
14092 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14093 {
14094 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14095 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014096 .subdevice = HDA_SUBDEV_AMP_FLAG,
Kailang Yang60db6b52008-08-26 13:13:00 +020014097 .info = snd_hda_mixer_amp_switch_info,
14098 .get = snd_hda_mixer_amp_switch_get,
14099 .put = alc268_acer_master_sw_put,
14100 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14101 },
14102 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14103 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014104 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014105 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14106 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014107 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang60db6b52008-08-26 13:13:00 +020014108 { }
14109};
14110
Tony Vroon64154832008-11-06 15:08:49 +000014111static struct snd_kcontrol_new alc269_lifebook_mixer[] = {
14112 /* output mixer control */
14113 HDA_BIND_VOL("Master Playback Volume", &alc268_acer_bind_master_vol),
14114 {
14115 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
14116 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +010014117 .subdevice = HDA_SUBDEV_AMP_FLAG,
Tony Vroon64154832008-11-06 15:08:49 +000014118 .info = snd_hda_mixer_amp_switch_info,
14119 .get = snd_hda_mixer_amp_switch_get,
14120 .put = alc268_acer_master_sw_put,
14121 .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
14122 },
14123 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
14124 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014125 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014126 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
14127 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014128 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014129 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x0b, 0x03, HDA_INPUT),
14130 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x0b, 0x03, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014131 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x1b, 0, HDA_INPUT),
Tony Vroon64154832008-11-06 15:08:49 +000014132 { }
14133};
14134
Kailang Yang84898e82010-02-04 14:16:14 +010014135static struct snd_kcontrol_new alc269_laptop_mixer[] = {
Takashi Iwaiaa202452009-07-03 15:00:54 +020014136 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014137 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwaiaa202452009-07-03 15:00:54 +020014138 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
Darren Salt508f7112009-07-08 15:29:49 +010014139 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yangf53281e2008-07-18 12:36:43 +020014140 { } /* end */
14141};
14142
Kailang Yang84898e82010-02-04 14:16:14 +010014143static struct snd_kcontrol_new alc269vb_laptop_mixer[] = {
14144 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
14145 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14146 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
14147 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
14148 { } /* end */
14149};
14150
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014151static struct snd_kcontrol_new alc269_asus_mixer[] = {
14152 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
14153 HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x0, HDA_INPUT),
14154 { } /* end */
14155};
14156
Kailang Yangf6a92242007-12-13 16:52:54 +010014157/* capture mixer elements */
Kailang Yang84898e82010-02-04 14:16:14 +010014158static struct snd_kcontrol_new alc269_laptop_analog_capture_mixer[] = {
14159 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14160 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014161 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14162 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014163 { } /* end */
14164};
14165
14166static struct snd_kcontrol_new alc269_laptop_digital_capture_mixer[] = {
Kailang Yangf53281e2008-07-18 12:36:43 +020014167 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
14168 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014169 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Takashi Iwai26f5df22008-11-03 17:39:46 +010014170 { } /* end */
14171};
14172
Kailang Yang84898e82010-02-04 14:16:14 +010014173static struct snd_kcontrol_new alc269vb_laptop_analog_capture_mixer[] = {
14174 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14175 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014176 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
14177 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014178 { } /* end */
14179};
14180
14181static struct snd_kcontrol_new alc269vb_laptop_digital_capture_mixer[] = {
14182 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
14183 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010014184 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yang84898e82010-02-04 14:16:14 +010014185 { } /* end */
14186};
14187
Takashi Iwai26f5df22008-11-03 17:39:46 +010014188/* FSC amilo */
Kailang Yang84898e82010-02-04 14:16:14 +010014189#define alc269_fujitsu_mixer alc269_laptop_mixer
Kailang Yangf53281e2008-07-18 12:36:43 +020014190
Kailang Yang60db6b52008-08-26 13:13:00 +020014191static struct hda_verb alc269_quanta_fl1_verbs[] = {
14192 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14193 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14194 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14195 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14196 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14197 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14198 { }
14199};
14200
Tony Vroon64154832008-11-06 15:08:49 +000014201static struct hda_verb alc269_lifebook_verbs[] = {
14202 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14203 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01},
14204 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14205 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14206 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14207 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14208 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14209 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
14210 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14211 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14212 { }
14213};
14214
Kailang Yang60db6b52008-08-26 13:13:00 +020014215/* toggle speaker-output according to the hp-jack state */
14216static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec)
14217{
14218 unsigned int present;
14219 unsigned char bits;
14220
Wu Fengguang864f92b2009-11-18 12:38:02 +080014221 present = snd_hda_jack_detect(codec, 0x15);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014222 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014223 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014224 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014225 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014226 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014227
14228 snd_hda_codec_write(codec, 0x20, 0,
14229 AC_VERB_SET_COEF_INDEX, 0x0c);
14230 snd_hda_codec_write(codec, 0x20, 0,
14231 AC_VERB_SET_PROC_COEF, 0x680);
14232
14233 snd_hda_codec_write(codec, 0x20, 0,
14234 AC_VERB_SET_COEF_INDEX, 0x0c);
14235 snd_hda_codec_write(codec, 0x20, 0,
14236 AC_VERB_SET_PROC_COEF, 0x480);
14237}
14238
Tony Vroon64154832008-11-06 15:08:49 +000014239/* toggle speaker-output according to the hp-jacks state */
14240static void alc269_lifebook_speaker_automute(struct hda_codec *codec)
14241{
14242 unsigned int present;
14243 unsigned char bits;
14244
14245 /* Check laptop headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014246 present = snd_hda_jack_detect(codec, 0x15);
Tony Vroon64154832008-11-06 15:08:49 +000014247
14248 /* Check port replicator headphone socket */
Wu Fengguang864f92b2009-11-18 12:38:02 +080014249 present |= snd_hda_jack_detect(codec, 0x1a);
Tony Vroon64154832008-11-06 15:08:49 +000014250
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014251 bits = present ? HDA_AMP_MUTE : 0;
Tony Vroon64154832008-11-06 15:08:49 +000014252 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014253 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014254 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014255 HDA_AMP_MUTE, bits);
Tony Vroon64154832008-11-06 15:08:49 +000014256
14257 snd_hda_codec_write(codec, 0x20, 0,
14258 AC_VERB_SET_COEF_INDEX, 0x0c);
14259 snd_hda_codec_write(codec, 0x20, 0,
14260 AC_VERB_SET_PROC_COEF, 0x680);
14261
14262 snd_hda_codec_write(codec, 0x20, 0,
14263 AC_VERB_SET_COEF_INDEX, 0x0c);
14264 snd_hda_codec_write(codec, 0x20, 0,
14265 AC_VERB_SET_PROC_COEF, 0x480);
14266}
14267
Tony Vroon64154832008-11-06 15:08:49 +000014268static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec)
14269{
14270 unsigned int present_laptop;
14271 unsigned int present_dock;
14272
Wu Fengguang864f92b2009-11-18 12:38:02 +080014273 present_laptop = snd_hda_jack_detect(codec, 0x18);
14274 present_dock = snd_hda_jack_detect(codec, 0x1b);
Tony Vroon64154832008-11-06 15:08:49 +000014275
14276 /* Laptop mic port overrides dock mic port, design decision */
14277 if (present_dock)
14278 snd_hda_codec_write(codec, 0x23, 0,
14279 AC_VERB_SET_CONNECT_SEL, 0x3);
14280 if (present_laptop)
14281 snd_hda_codec_write(codec, 0x23, 0,
14282 AC_VERB_SET_CONNECT_SEL, 0x0);
14283 if (!present_dock && !present_laptop)
14284 snd_hda_codec_write(codec, 0x23, 0,
14285 AC_VERB_SET_CONNECT_SEL, 0x1);
14286}
14287
Kailang Yang60db6b52008-08-26 13:13:00 +020014288static void alc269_quanta_fl1_unsol_event(struct hda_codec *codec,
14289 unsigned int res)
14290{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014291 switch (res >> 26) {
14292 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014293 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014294 break;
14295 case ALC880_MIC_EVENT:
14296 alc_mic_automute(codec);
14297 break;
14298 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014299}
14300
Tony Vroon64154832008-11-06 15:08:49 +000014301static void alc269_lifebook_unsol_event(struct hda_codec *codec,
14302 unsigned int res)
14303{
14304 if ((res >> 26) == ALC880_HP_EVENT)
14305 alc269_lifebook_speaker_automute(codec);
14306 if ((res >> 26) == ALC880_MIC_EVENT)
14307 alc269_lifebook_mic_autoswitch(codec);
14308}
14309
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014310static void alc269_quanta_fl1_setup(struct hda_codec *codec)
14311{
14312 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014313 spec->autocfg.hp_pins[0] = 0x15;
14314 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014315 spec->ext_mic.pin = 0x18;
14316 spec->ext_mic.mux_idx = 0;
14317 spec->int_mic.pin = 0x19;
14318 spec->int_mic.mux_idx = 1;
14319 spec->auto_mic = 1;
14320}
14321
Kailang Yang60db6b52008-08-26 13:13:00 +020014322static void alc269_quanta_fl1_init_hook(struct hda_codec *codec)
14323{
14324 alc269_quanta_fl1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014325 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014326}
14327
Tony Vroon64154832008-11-06 15:08:49 +000014328static void alc269_lifebook_init_hook(struct hda_codec *codec)
14329{
14330 alc269_lifebook_speaker_automute(codec);
14331 alc269_lifebook_mic_autoswitch(codec);
14332}
14333
Kailang Yang84898e82010-02-04 14:16:14 +010014334static struct hda_verb alc269_laptop_dmic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014335 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14336 {0x23, AC_VERB_SET_CONNECT_SEL, 0x05},
14337 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14338 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14339 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14340 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14341 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14342 {}
14343};
14344
Kailang Yang84898e82010-02-04 14:16:14 +010014345static struct hda_verb alc269_laptop_amic_init_verbs[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014346 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
14347 {0x23, AC_VERB_SET_CONNECT_SEL, 0x01},
14348 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14349 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, (0x701b | (0x00 << 8))},
14350 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14351 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14352 {}
14353};
14354
Kailang Yang84898e82010-02-04 14:16:14 +010014355static struct hda_verb alc269vb_laptop_dmic_init_verbs[] = {
14356 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14357 {0x22, AC_VERB_SET_CONNECT_SEL, 0x06},
14358 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14359 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14360 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14361 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14362 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14363 {}
14364};
14365
14366static struct hda_verb alc269vb_laptop_amic_init_verbs[] = {
14367 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01},
14368 {0x22, AC_VERB_SET_CONNECT_SEL, 0x01},
14369 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, 0xb026 },
14370 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, (0x7019 | (0x00 << 8))},
14371 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14372 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14373 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14374 {}
14375};
14376
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014377static struct hda_verb alc271_acer_dmic_verbs[] = {
14378 {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
14379 {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
14380 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14381 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14382 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14383 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14384 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00},
14385 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
14386 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
14387 {0x22, AC_VERB_SET_CONNECT_SEL, 6},
14388 { }
14389};
14390
Kailang Yang60db6b52008-08-26 13:13:00 +020014391/* toggle speaker-output according to the hp-jack state */
14392static void alc269_speaker_automute(struct hda_codec *codec)
14393{
Kailang Yangebb83ee2009-12-17 12:23:00 +010014394 struct alc_spec *spec = codec->spec;
14395 unsigned int nid = spec->autocfg.hp_pins[0];
Kailang Yang60db6b52008-08-26 13:13:00 +020014396 unsigned int present;
14397 unsigned char bits;
14398
Kailang Yangebb83ee2009-12-17 12:23:00 +010014399 present = snd_hda_jack_detect(codec, nid);
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014400 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yang60db6b52008-08-26 13:13:00 +020014401 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014402 HDA_AMP_MUTE, bits);
Kailang Yang60db6b52008-08-26 13:13:00 +020014403 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020014404 HDA_AMP_MUTE, bits);
Kailang Yangbf1b0222010-10-21 08:49:56 +020014405 alc_report_jack(codec, nid);
Kailang Yang60db6b52008-08-26 13:13:00 +020014406}
14407
Kailang Yang60db6b52008-08-26 13:13:00 +020014408/* unsolicited event for HP jack sensing */
Kailang Yang84898e82010-02-04 14:16:14 +010014409static void alc269_laptop_unsol_event(struct hda_codec *codec,
Kailang Yang60db6b52008-08-26 13:13:00 +020014410 unsigned int res)
14411{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014412 switch (res >> 26) {
14413 case ALC880_HP_EVENT:
Kailang Yang60db6b52008-08-26 13:13:00 +020014414 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014415 break;
14416 case ALC880_MIC_EVENT:
14417 alc_mic_automute(codec);
14418 break;
14419 }
Kailang Yang60db6b52008-08-26 13:13:00 +020014420}
14421
Kailang Yang226b1ec2010-04-09 11:01:20 +020014422static void alc269_laptop_amic_setup(struct hda_codec *codec)
14423{
14424 struct alc_spec *spec = codec->spec;
14425 spec->autocfg.hp_pins[0] = 0x15;
14426 spec->autocfg.speaker_pins[0] = 0x14;
14427 spec->ext_mic.pin = 0x18;
14428 spec->ext_mic.mux_idx = 0;
14429 spec->int_mic.pin = 0x19;
14430 spec->int_mic.mux_idx = 1;
14431 spec->auto_mic = 1;
14432}
14433
Kailang Yang84898e82010-02-04 14:16:14 +010014434static void alc269_laptop_dmic_setup(struct hda_codec *codec)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014435{
14436 struct alc_spec *spec = codec->spec;
Takashi Iwai20645d72010-03-02 11:14:01 +010014437 spec->autocfg.hp_pins[0] = 0x15;
14438 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014439 spec->ext_mic.pin = 0x18;
14440 spec->ext_mic.mux_idx = 0;
14441 spec->int_mic.pin = 0x12;
14442 spec->int_mic.mux_idx = 5;
14443 spec->auto_mic = 1;
14444}
14445
Kailang Yang226b1ec2010-04-09 11:01:20 +020014446static void alc269vb_laptop_amic_setup(struct hda_codec *codec)
Kailang Yang84898e82010-02-04 14:16:14 +010014447{
14448 struct alc_spec *spec = codec->spec;
Kailang Yang226b1ec2010-04-09 11:01:20 +020014449 spec->autocfg.hp_pins[0] = 0x21;
Takashi Iwai20645d72010-03-02 11:14:01 +010014450 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014451 spec->ext_mic.pin = 0x18;
14452 spec->ext_mic.mux_idx = 0;
14453 spec->int_mic.pin = 0x19;
14454 spec->int_mic.mux_idx = 1;
14455 spec->auto_mic = 1;
14456}
14457
Kailang Yang226b1ec2010-04-09 11:01:20 +020014458static void alc269vb_laptop_dmic_setup(struct hda_codec *codec)
14459{
14460 struct alc_spec *spec = codec->spec;
14461 spec->autocfg.hp_pins[0] = 0x21;
14462 spec->autocfg.speaker_pins[0] = 0x14;
14463 spec->ext_mic.pin = 0x18;
14464 spec->ext_mic.mux_idx = 0;
14465 spec->int_mic.pin = 0x12;
14466 spec->int_mic.mux_idx = 6;
14467 spec->auto_mic = 1;
14468}
14469
Kailang Yang84898e82010-02-04 14:16:14 +010014470static void alc269_laptop_inithook(struct hda_codec *codec)
Kailang Yang60db6b52008-08-26 13:13:00 +020014471{
14472 alc269_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014473 alc_mic_automute(codec);
Kailang Yang60db6b52008-08-26 13:13:00 +020014474}
14475
Kailang Yangf6a92242007-12-13 16:52:54 +010014476/*
14477 * generic initialization of ADC, input mixers and output mixers
14478 */
14479static struct hda_verb alc269_init_verbs[] = {
14480 /*
14481 * Unmute ADC0 and set the default input to mic-in
14482 */
Kailang Yang84898e82010-02-04 14:16:14 +010014483 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangf6a92242007-12-13 16:52:54 +010014484
14485 /*
Kailang Yang84898e82010-02-04 14:16:14 +010014486 * Set up output mixers (0x02 - 0x03)
Kailang Yangf6a92242007-12-13 16:52:54 +010014487 */
14488 /* set vol=0 to output mixers */
14489 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14490 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14491
14492 /* set up input amps for analog loopback */
14493 /* Amp Indices: DAC = 0, mixer = 1 */
14494 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14495 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14496 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14497 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14498 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14499 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14500
14501 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14502 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14503 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14504 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14505 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14506 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14507 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14508
14509 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14510 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf6a92242007-12-13 16:52:54 +010014511
Kailang Yang84898e82010-02-04 14:16:14 +010014512 /* FIXME: use Mux-type input source selection */
Kailang Yangf6a92242007-12-13 16:52:54 +010014513 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14514 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yang84898e82010-02-04 14:16:14 +010014515 {0x23, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangf6a92242007-12-13 16:52:54 +010014516
14517 /* set EAPD */
14518 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yang84898e82010-02-04 14:16:14 +010014519 { }
14520};
14521
14522static struct hda_verb alc269vb_init_verbs[] = {
14523 /*
14524 * Unmute ADC0 and set the default input to mic-in
14525 */
14526 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14527
14528 /*
14529 * Set up output mixers (0x02 - 0x03)
14530 */
14531 /* set vol=0 to output mixers */
14532 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14533 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
14534
14535 /* set up input amps for analog loopback */
14536 /* Amp Indices: DAC = 0, mixer = 1 */
14537 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14538 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14539 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14540 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14541 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
14542 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
14543
14544 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14545 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
14546 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
14547 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14548 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
14549 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14550 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
14551
14552 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14553 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
14554
14555 /* FIXME: use Mux-type input source selection */
14556 /* Mixer elements: 0x18, 19, 1a, 1b, 1d, 0b */
14557 /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
14558 {0x22, AC_VERB_SET_CONNECT_SEL, 0x00},
14559
14560 /* set EAPD */
14561 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
Kailang Yangf6a92242007-12-13 16:52:54 +010014562 { }
14563};
14564
Takashi Iwai9d0b71b2009-08-24 14:10:30 +020014565#define alc269_auto_create_multi_out_ctls \
14566 alc268_auto_create_multi_out_ctls
Takashi Iwai05f5f472009-08-25 13:10:18 +020014567#define alc269_auto_create_input_ctls \
14568 alc268_auto_create_input_ctls
Kailang Yangf6a92242007-12-13 16:52:54 +010014569
14570#ifdef CONFIG_SND_HDA_POWER_SAVE
14571#define alc269_loopbacks alc880_loopbacks
14572#endif
14573
Sasha Alexandrdef319f2009-06-16 16:00:15 -040014574/* pcm configuration: identical with ALC880 */
Kailang Yangf6a92242007-12-13 16:52:54 +010014575#define alc269_pcm_analog_playback alc880_pcm_analog_playback
14576#define alc269_pcm_analog_capture alc880_pcm_analog_capture
14577#define alc269_pcm_digital_playback alc880_pcm_digital_playback
14578#define alc269_pcm_digital_capture alc880_pcm_digital_capture
14579
Takashi Iwaif03d3112009-03-05 14:18:16 +010014580static struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
14581 .substreams = 1,
14582 .channels_min = 2,
14583 .channels_max = 8,
14584 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14585 /* NID is set in alc_build_pcms */
14586 .ops = {
14587 .open = alc880_playback_pcm_open,
14588 .prepare = alc880_playback_pcm_prepare,
14589 .cleanup = alc880_playback_pcm_cleanup
14590 },
14591};
14592
14593static struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
14594 .substreams = 1,
14595 .channels_min = 2,
14596 .channels_max = 2,
14597 .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
14598 /* NID is set in alc_build_pcms */
14599};
14600
Takashi Iwaiad358792010-03-30 18:00:59 +020014601#ifdef CONFIG_SND_HDA_POWER_SAVE
14602static int alc269_mic2_for_mute_led(struct hda_codec *codec)
14603{
14604 switch (codec->subsystem_id) {
14605 case 0x103c1586:
14606 return 1;
14607 }
14608 return 0;
14609}
14610
14611static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
14612{
14613 /* update mute-LED according to the speaker mute state */
14614 if (nid == 0x01 || nid == 0x14) {
14615 int pinval;
14616 if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
14617 HDA_AMP_MUTE)
14618 pinval = 0x24;
14619 else
14620 pinval = 0x20;
14621 /* mic2 vref pin is used for mute LED control */
Takashi Iwaia68d5a52010-03-30 18:03:44 +020014622 snd_hda_codec_update_cache(codec, 0x19, 0,
14623 AC_VERB_SET_PIN_WIDGET_CONTROL,
14624 pinval);
Takashi Iwaiad358792010-03-30 18:00:59 +020014625 }
14626 return alc_check_power_status(codec, nid);
14627}
14628#endif /* CONFIG_SND_HDA_POWER_SAVE */
14629
Takashi Iwai840b64c2010-07-13 22:49:01 +020014630static int alc275_setup_dual_adc(struct hda_codec *codec)
14631{
14632 struct alc_spec *spec = codec->spec;
14633
14634 if (codec->vendor_id != 0x10ec0275 || !spec->auto_mic)
14635 return 0;
14636 if ((spec->ext_mic.pin >= 0x18 && spec->int_mic.pin <= 0x13) ||
14637 (spec->ext_mic.pin <= 0x12 && spec->int_mic.pin >= 0x18)) {
14638 if (spec->ext_mic.pin <= 0x12) {
14639 spec->private_adc_nids[0] = 0x08;
14640 spec->private_adc_nids[1] = 0x11;
14641 spec->private_capsrc_nids[0] = 0x23;
14642 spec->private_capsrc_nids[1] = 0x22;
14643 } else {
14644 spec->private_adc_nids[0] = 0x11;
14645 spec->private_adc_nids[1] = 0x08;
14646 spec->private_capsrc_nids[0] = 0x22;
14647 spec->private_capsrc_nids[1] = 0x23;
14648 }
14649 spec->adc_nids = spec->private_adc_nids;
14650 spec->capsrc_nids = spec->private_capsrc_nids;
14651 spec->num_adc_nids = 2;
14652 spec->dual_adc_switch = 1;
14653 snd_printdd("realtek: enabling dual ADC switchg (%02x:%02x)\n",
14654 spec->adc_nids[0], spec->adc_nids[1]);
14655 return 1;
14656 }
14657 return 0;
14658}
14659
Takashi Iwaid433a672010-09-20 15:11:54 +020014660/* different alc269-variants */
14661enum {
14662 ALC269_TYPE_NORMAL,
Kailang Yang48c88e82010-11-23 08:56:16 +010014663 ALC269_TYPE_ALC258,
Takashi Iwaid433a672010-09-20 15:11:54 +020014664 ALC269_TYPE_ALC259,
Kailang Yang48c88e82010-11-23 08:56:16 +010014665 ALC269_TYPE_ALC269VB,
14666 ALC269_TYPE_ALC270,
Takashi Iwaid433a672010-09-20 15:11:54 +020014667 ALC269_TYPE_ALC271X,
14668};
14669
Kailang Yangf6a92242007-12-13 16:52:54 +010014670/*
14671 * BIOS auto configuration
14672 */
14673static int alc269_parse_auto_config(struct hda_codec *codec)
14674{
14675 struct alc_spec *spec = codec->spec;
Takashi Iwaicfb9fb52009-02-06 17:34:03 +010014676 int err;
Kailang Yangf6a92242007-12-13 16:52:54 +010014677 static hda_nid_t alc269_ignore[] = { 0x1d, 0 };
14678
14679 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
14680 alc269_ignore);
14681 if (err < 0)
14682 return err;
14683
14684 err = alc269_auto_create_multi_out_ctls(spec, &spec->autocfg);
14685 if (err < 0)
14686 return err;
Takashi Iwaif3550d12010-09-20 15:09:03 +020014687 if (spec->codec_variant == ALC269_TYPE_NORMAL)
14688 err = alc269_auto_create_input_ctls(codec, &spec->autocfg);
14689 else
14690 err = alc_auto_create_input_ctls(codec, &spec->autocfg, 0,
14691 0x22, 0);
Kailang Yangf6a92242007-12-13 16:52:54 +010014692 if (err < 0)
14693 return err;
14694
14695 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
14696
Takashi Iwai757899a2010-07-30 10:48:14 +020014697 alc_auto_parse_digital(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014698
Takashi Iwai603c4012008-07-30 15:01:44 +020014699 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010014700 add_mixer(spec, spec->kctls.list);
Kailang Yangf6a92242007-12-13 16:52:54 +010014701
Takashi Iwaid433a672010-09-20 15:11:54 +020014702 if (spec->codec_variant != ALC269_TYPE_NORMAL) {
Kailang Yang84898e82010-02-04 14:16:14 +010014703 add_verb(spec, alc269vb_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014704 alc_ssid_check(codec, 0, 0x1b, 0x14, 0x21);
Kailang Yang84898e82010-02-04 14:16:14 +010014705 } else {
14706 add_verb(spec, alc269_init_verbs);
Kailang Yang6227cdc2010-02-25 08:36:52 +010014707 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Kailang Yang84898e82010-02-04 14:16:14 +010014708 }
14709
Kailang Yangf6a92242007-12-13 16:52:54 +010014710 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020014711 spec->input_mux = &spec->private_imux[0];
Takashi Iwai840b64c2010-07-13 22:49:01 +020014712
14713 if (!alc275_setup_dual_adc(codec))
14714 fillup_priv_adc_nids(codec, alc269_adc_candidates,
14715 sizeof(alc269_adc_candidates));
Takashi Iwai66946352010-03-29 17:21:45 +020014716
Takashi Iwaie01bf502008-08-21 16:25:07 +020014717 /* set default input source */
Takashi Iwai840b64c2010-07-13 22:49:01 +020014718 if (!spec->dual_adc_switch)
Takashi Iwai748cce42010-08-04 07:37:39 +020014719 select_or_unmute_capsrc(codec, spec->capsrc_nids[0],
14720 spec->input_mux->items[0].index);
Kailang Yangf6a92242007-12-13 16:52:54 +010014721
14722 err = alc_auto_add_mic_boost(codec);
14723 if (err < 0)
14724 return err;
14725
Takashi Iwai7e0e44d2009-02-19 08:15:49 +010014726 if (!spec->cap_mixer && !spec->no_analog)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020014727 set_capture_mixer(codec);
Kailang Yangf53281e2008-07-18 12:36:43 +020014728
Kailang Yangf6a92242007-12-13 16:52:54 +010014729 return 1;
14730}
14731
Takashi Iwaie9af4f32009-08-29 23:23:08 +020014732#define alc269_auto_init_multi_out alc268_auto_init_multi_out
14733#define alc269_auto_init_hp_out alc268_auto_init_hp_out
Kailang Yangf6a92242007-12-13 16:52:54 +010014734#define alc269_auto_init_analog_input alc882_auto_init_analog_input
14735
14736
14737/* init callback for auto-configuration model -- overriding the default init */
14738static void alc269_auto_init(struct hda_codec *codec)
14739{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014740 struct alc_spec *spec = codec->spec;
Kailang Yangf6a92242007-12-13 16:52:54 +010014741 alc269_auto_init_multi_out(codec);
14742 alc269_auto_init_hp_out(codec);
14743 alc269_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020014744 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010014745 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020014746 alc_inithook(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010014747}
14748
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014749#ifdef SND_HDA_NEEDS_RESUME
14750static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
14751{
14752 int val = alc_read_coef_idx(codec, 0x04);
14753 if (power_up)
14754 val |= 1 << 11;
14755 else
14756 val &= ~(1 << 11);
14757 alc_write_coef_idx(codec, 0x04, val);
14758}
14759
Kailang Yang977ddd62010-09-15 10:02:29 +020014760#ifdef CONFIG_SND_HDA_POWER_SAVE
14761static int alc269_suspend(struct hda_codec *codec, pm_message_t state)
14762{
14763 struct alc_spec *spec = codec->spec;
Kailang Yang977ddd62010-09-15 10:02:29 +020014764
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014765 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017)
14766 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014767 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014768 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014769 msleep(150);
14770 }
14771
14772 alc_shutup(codec);
14773 if (spec && spec->power_hook)
14774 spec->power_hook(codec);
14775 return 0;
14776}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014777#endif /* CONFIG_SND_HDA_POWER_SAVE */
14778
Kailang Yang977ddd62010-09-15 10:02:29 +020014779static int alc269_resume(struct hda_codec *codec)
14780{
Kailang Yang977ddd62010-09-15 10:02:29 +020014781 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014782 alc269_toggle_power_output(codec, 0);
Kailang Yang977ddd62010-09-15 10:02:29 +020014783 msleep(150);
14784 }
14785
14786 codec->patch_ops.init(codec);
14787
14788 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014789 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014790 msleep(200);
14791 }
14792
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014793 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018)
14794 alc269_toggle_power_output(codec, 1);
Kailang Yang977ddd62010-09-15 10:02:29 +020014795
14796 snd_hda_codec_resume_amp(codec);
14797 snd_hda_codec_resume_cache(codec);
Takashi Iwai9e5341b2010-09-21 09:57:06 +020014798 hda_call_check_power_status(codec, 0x01);
Kailang Yang977ddd62010-09-15 10:02:29 +020014799 return 0;
14800}
Takashi Iwai0ec33d12010-09-20 15:20:52 +020014801#endif /* SND_HDA_NEEDS_RESUME */
Kailang Yang977ddd62010-09-15 10:02:29 +020014802
Takashi Iwaiff818c22010-04-12 08:59:25 +020014803enum {
14804 ALC269_FIXUP_SONY_VAIO,
Kailang Yang27855912010-12-21 09:09:53 +010014805 ALC275_FIX_SONY_VAIO_GPIO2,
David Henningsson145a9022010-09-16 10:07:53 +020014806 ALC269_FIXUP_DELL_M101Z,
David Henningsson022c92b2010-12-17 20:43:04 +010014807 ALC269_FIXUP_SKU_IGNORE,
David Henningssonac612402010-12-15 09:18:18 +010014808 ALC269_FIXUP_ASUS_G73JW,
Takashi Iwaiff818c22010-04-12 08:59:25 +020014809};
14810
Takashi Iwaiff818c22010-04-12 08:59:25 +020014811static const struct alc_fixup alc269_fixups[] = {
14812 [ALC269_FIXUP_SONY_VAIO] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020014813 .verbs = (const struct hda_verb[]) {
14814 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
14815 {}
14816 }
Takashi Iwaiff818c22010-04-12 08:59:25 +020014817 },
Kailang Yang27855912010-12-21 09:09:53 +010014818 [ALC275_FIX_SONY_VAIO_GPIO2] = {
14819 .verbs = (const struct hda_verb[]) {
14820 {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
14821 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
14822 {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
14823 { }
14824 }
14825 },
David Henningsson145a9022010-09-16 10:07:53 +020014826 [ALC269_FIXUP_DELL_M101Z] = {
14827 .verbs = (const struct hda_verb[]) {
14828 /* Enables internal speaker */
14829 {0x20, AC_VERB_SET_COEF_INDEX, 13},
14830 {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
14831 {}
14832 }
14833 },
David Henningsson022c92b2010-12-17 20:43:04 +010014834 [ALC269_FIXUP_SKU_IGNORE] = {
David Henningssonfe67b242010-12-15 08:01:46 +010014835 .sku = ALC_FIXUP_SKU_IGNORE,
14836 },
David Henningssonac612402010-12-15 09:18:18 +010014837 [ALC269_FIXUP_ASUS_G73JW] = {
14838 .pins = (const struct alc_pincfg[]) {
14839 { 0x17, 0x99130111 }, /* subwoofer */
14840 { }
14841 }
14842 },
Takashi Iwaiff818c22010-04-12 08:59:25 +020014843};
14844
14845static struct snd_pci_quirk alc269_fixup_tbl[] = {
Kailang Yang27855912010-12-21 09:09:53 +010014846 SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
14847 SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
14848 SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2),
Takashi Iwaiabdd8f52010-09-21 17:38:14 +020014849 SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
David Henningsson145a9022010-09-16 10:07:53 +020014850 SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
David Henningsson022c92b2010-12-17 20:43:04 +010014851 SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
14852 SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
David Henningssonac612402010-12-15 09:18:18 +010014853 SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014854 {}
14855};
14856
14857
Kailang Yangf6a92242007-12-13 16:52:54 +010014858/*
14859 * configuration and preset
14860 */
14861static const char *alc269_models[ALC269_MODEL_LAST] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014862 [ALC269_BASIC] = "basic",
Takashi Iwai2922c9a2008-08-27 18:12:42 +020014863 [ALC269_QUANTA_FL1] = "quanta",
Kailang Yang84898e82010-02-04 14:16:14 +010014864 [ALC269_AMIC] = "laptop-amic",
14865 [ALC269_DMIC] = "laptop-dmic",
Tony Vroon64154832008-11-06 15:08:49 +000014866 [ALC269_FUJITSU] = "fujitsu",
Takashi Iwai3d3792c2009-09-11 07:50:47 +020014867 [ALC269_LIFEBOOK] = "lifebook",
14868 [ALC269_AUTO] = "auto",
Kailang Yangf6a92242007-12-13 16:52:54 +010014869};
14870
14871static struct snd_pci_quirk alc269_cfg_tbl[] = {
Kailang Yang60db6b52008-08-26 13:13:00 +020014872 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1),
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020014873 SND_PCI_QUIRK(0x1025, 0x047c, "ACER ZGA", ALC271_ACER),
Kailang Yangf53281e2008-07-18 12:36:43 +020014874 SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
Kailang Yang84898e82010-02-04 14:16:14 +010014875 ALC269_AMIC),
14876 SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269VB_AMIC),
14877 SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269VB_AMIC),
14878 SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269VB_AMIC),
14879 SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_AMIC),
14880 SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269VB_AMIC),
14881 SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269VB_AMIC),
14882 SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269VB_AMIC),
14883 SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269VB_AMIC),
14884 SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_AMIC),
14885 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_AMIC),
14886 SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_AMIC),
14887 SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_AMIC),
14888 SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_AMIC),
14889 SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_AMIC),
14890 SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_AMIC),
14891 SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_AMIC),
14892 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_AMIC),
14893 SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_AMIC),
14894 SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_AMIC),
14895 SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_AMIC),
14896 SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_AMIC),
14897 SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_AMIC),
14898 SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_AMIC),
14899 SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_AMIC),
14900 SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_AMIC),
14901 SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_AMIC),
14902 SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_AMIC),
14903 SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_AMIC),
14904 SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_AMIC),
14905 SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_AMIC),
14906 SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_AMIC),
14907 SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_DMIC),
14908 SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_AMIC),
14909 SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_AMIC),
14910 SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_AMIC),
14911 SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_AMIC),
Kailang Yangf53281e2008-07-18 12:36:43 +020014912 SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901",
Kailang Yang84898e82010-02-04 14:16:14 +010014913 ALC269_DMIC),
Kailang Yang60db6b52008-08-26 13:13:00 +020014914 SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101",
Kailang Yang84898e82010-02-04 14:16:14 +010014915 ALC269_DMIC),
14916 SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_DMIC),
14917 SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_DMIC),
Takashi Iwaiff818c22010-04-12 08:59:25 +020014918 SND_PCI_QUIRK(0x104d, 0x9071, "Sony VAIO", ALC269_AUTO),
Tony Vroon64154832008-11-06 15:08:49 +000014919 SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK),
Kailang Yang61c2d2b2010-02-25 08:49:06 +010014920 SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_DMIC),
14921 SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU),
14922 SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_AMIC),
14923 SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_AMIC),
14924 SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_DMIC),
14925 SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_DMIC),
Kailang Yangf6a92242007-12-13 16:52:54 +010014926 {}
14927};
14928
14929static struct alc_config_preset alc269_presets[] = {
14930 [ALC269_BASIC] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010014931 .mixers = { alc269_base_mixer },
Kailang Yangf6a92242007-12-13 16:52:54 +010014932 .init_verbs = { alc269_init_verbs },
14933 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14934 .dac_nids = alc269_dac_nids,
14935 .hp_nid = 0x03,
14936 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14937 .channel_mode = alc269_modes,
14938 .input_mux = &alc269_capture_source,
14939 },
Kailang Yang60db6b52008-08-26 13:13:00 +020014940 [ALC269_QUANTA_FL1] = {
14941 .mixers = { alc269_quanta_fl1_mixer },
14942 .init_verbs = { alc269_init_verbs, alc269_quanta_fl1_verbs },
14943 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14944 .dac_nids = alc269_dac_nids,
14945 .hp_nid = 0x03,
14946 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14947 .channel_mode = alc269_modes,
14948 .input_mux = &alc269_capture_source,
14949 .unsol_event = alc269_quanta_fl1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020014950 .setup = alc269_quanta_fl1_setup,
Kailang Yang60db6b52008-08-26 13:13:00 +020014951 .init_hook = alc269_quanta_fl1_init_hook,
14952 },
Kailang Yang84898e82010-02-04 14:16:14 +010014953 [ALC269_AMIC] = {
14954 .mixers = { alc269_laptop_mixer },
14955 .cap_mixer = alc269_laptop_analog_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014956 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014957 alc269_laptop_amic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014958 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14959 .dac_nids = alc269_dac_nids,
14960 .hp_nid = 0x03,
14961 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14962 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014963 .unsol_event = alc269_laptop_unsol_event,
14964 .setup = alc269_laptop_amic_setup,
14965 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020014966 },
Kailang Yang84898e82010-02-04 14:16:14 +010014967 [ALC269_DMIC] = {
14968 .mixers = { alc269_laptop_mixer },
14969 .cap_mixer = alc269_laptop_digital_capture_mixer,
Kailang Yangf53281e2008-07-18 12:36:43 +020014970 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010014971 alc269_laptop_dmic_init_verbs },
Kailang Yangf53281e2008-07-18 12:36:43 +020014972 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14973 .dac_nids = alc269_dac_nids,
14974 .hp_nid = 0x03,
14975 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14976 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010014977 .unsol_event = alc269_laptop_unsol_event,
14978 .setup = alc269_laptop_dmic_setup,
14979 .init_hook = alc269_laptop_inithook,
14980 },
14981 [ALC269VB_AMIC] = {
14982 .mixers = { alc269vb_laptop_mixer },
14983 .cap_mixer = alc269vb_laptop_analog_capture_mixer,
14984 .init_verbs = { alc269vb_init_verbs,
14985 alc269vb_laptop_amic_init_verbs },
14986 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
14987 .dac_nids = alc269_dac_nids,
14988 .hp_nid = 0x03,
14989 .num_channel_mode = ARRAY_SIZE(alc269_modes),
14990 .channel_mode = alc269_modes,
14991 .unsol_event = alc269_laptop_unsol_event,
Kailang Yang226b1ec2010-04-09 11:01:20 +020014992 .setup = alc269vb_laptop_amic_setup,
Kailang Yang84898e82010-02-04 14:16:14 +010014993 .init_hook = alc269_laptop_inithook,
14994 },
14995 [ALC269VB_DMIC] = {
14996 .mixers = { alc269vb_laptop_mixer },
14997 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
14998 .init_verbs = { alc269vb_init_verbs,
14999 alc269vb_laptop_dmic_init_verbs },
15000 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15001 .dac_nids = alc269_dac_nids,
15002 .hp_nid = 0x03,
15003 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15004 .channel_mode = alc269_modes,
15005 .unsol_event = alc269_laptop_unsol_event,
15006 .setup = alc269vb_laptop_dmic_setup,
15007 .init_hook = alc269_laptop_inithook,
Kailang Yangf53281e2008-07-18 12:36:43 +020015008 },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015009 [ALC269_FUJITSU] = {
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010015010 .mixers = { alc269_fujitsu_mixer },
Kailang Yang84898e82010-02-04 14:16:14 +010015011 .cap_mixer = alc269_laptop_digital_capture_mixer,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015012 .init_verbs = { alc269_init_verbs,
Kailang Yang84898e82010-02-04 14:16:14 +010015013 alc269_laptop_dmic_init_verbs },
Takashi Iwai26f5df22008-11-03 17:39:46 +010015014 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15015 .dac_nids = alc269_dac_nids,
15016 .hp_nid = 0x03,
15017 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15018 .channel_mode = alc269_modes,
Kailang Yang84898e82010-02-04 14:16:14 +010015019 .unsol_event = alc269_laptop_unsol_event,
15020 .setup = alc269_laptop_dmic_setup,
15021 .init_hook = alc269_laptop_inithook,
Takashi Iwai26f5df22008-11-03 17:39:46 +010015022 },
Tony Vroon64154832008-11-06 15:08:49 +000015023 [ALC269_LIFEBOOK] = {
15024 .mixers = { alc269_lifebook_mixer },
15025 .init_verbs = { alc269_init_verbs, alc269_lifebook_verbs },
15026 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15027 .dac_nids = alc269_dac_nids,
15028 .hp_nid = 0x03,
15029 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15030 .channel_mode = alc269_modes,
15031 .input_mux = &alc269_capture_source,
15032 .unsol_event = alc269_lifebook_unsol_event,
15033 .init_hook = alc269_lifebook_init_hook,
15034 },
Kailang Yangfe3eb0a2010-08-06 10:02:57 +020015035 [ALC271_ACER] = {
15036 .mixers = { alc269_asus_mixer },
15037 .cap_mixer = alc269vb_laptop_digital_capture_mixer,
15038 .init_verbs = { alc269_init_verbs, alc271_acer_dmic_verbs },
15039 .num_dacs = ARRAY_SIZE(alc269_dac_nids),
15040 .dac_nids = alc269_dac_nids,
15041 .adc_nids = alc262_dmic_adc_nids,
15042 .num_adc_nids = ARRAY_SIZE(alc262_dmic_adc_nids),
15043 .capsrc_nids = alc262_dmic_capsrc_nids,
15044 .num_channel_mode = ARRAY_SIZE(alc269_modes),
15045 .channel_mode = alc269_modes,
15046 .input_mux = &alc269_capture_source,
15047 .dig_out_nid = ALC880_DIGOUT_NID,
15048 .unsol_event = alc_sku_unsol_event,
15049 .setup = alc269vb_laptop_dmic_setup,
15050 .init_hook = alc_inithook,
15051 },
Kailang Yangf6a92242007-12-13 16:52:54 +010015052};
15053
Kailang Yang977ddd62010-09-15 10:02:29 +020015054static int alc269_fill_coef(struct hda_codec *codec)
15055{
15056 int val;
15057
15058 if ((alc_read_coef_idx(codec, 0) & 0x00ff) < 0x015) {
15059 alc_write_coef_idx(codec, 0xf, 0x960b);
15060 alc_write_coef_idx(codec, 0xe, 0x8817);
15061 }
15062
15063 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x016) {
15064 alc_write_coef_idx(codec, 0xf, 0x960b);
15065 alc_write_coef_idx(codec, 0xe, 0x8814);
15066 }
15067
15068 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x017) {
15069 val = alc_read_coef_idx(codec, 0x04);
15070 /* Power up output pin */
15071 alc_write_coef_idx(codec, 0x04, val | (1<<11));
15072 }
15073
15074 if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) {
15075 val = alc_read_coef_idx(codec, 0xd);
15076 if ((val & 0x0c00) >> 10 != 0x1) {
15077 /* Capless ramp up clock control */
15078 alc_write_coef_idx(codec, 0xd, val | 1<<10);
15079 }
15080 val = alc_read_coef_idx(codec, 0x17);
15081 if ((val & 0x01c0) >> 6 != 0x4) {
15082 /* Class D power on reset */
15083 alc_write_coef_idx(codec, 0x17, val | 1<<7);
15084 }
15085 }
15086 return 0;
15087}
15088
Kailang Yangf6a92242007-12-13 16:52:54 +010015089static int patch_alc269(struct hda_codec *codec)
15090{
15091 struct alc_spec *spec;
Kailang Yang48c88e82010-11-23 08:56:16 +010015092 int board_config, coef;
Kailang Yangf6a92242007-12-13 16:52:54 +010015093 int err;
15094
15095 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15096 if (spec == NULL)
15097 return -ENOMEM;
15098
15099 codec->spec = spec;
15100
Kailang Yangda00c242010-03-19 11:23:45 +010015101 alc_auto_parse_customize_define(codec);
15102
Kailang Yangc793bec2010-12-21 09:14:13 +010015103 if (codec->vendor_id == 0x10ec0269) {
15104 coef = alc_read_coef_idx(codec, 0);
15105 if ((coef & 0x00f0) == 0x0010) {
15106 if (codec->bus->pci->subsystem_vendor == 0x1025 &&
15107 spec->cdefine.platform_type == 1) {
15108 alc_codec_rename(codec, "ALC271X");
15109 spec->codec_variant = ALC269_TYPE_ALC271X;
15110 } else if ((coef & 0xf000) == 0x1000) {
15111 spec->codec_variant = ALC269_TYPE_ALC270;
15112 } else if ((coef & 0xf000) == 0x2000) {
15113 alc_codec_rename(codec, "ALC259");
15114 spec->codec_variant = ALC269_TYPE_ALC259;
15115 } else if ((coef & 0xf000) == 0x3000) {
15116 alc_codec_rename(codec, "ALC258");
15117 spec->codec_variant = ALC269_TYPE_ALC258;
15118 } else {
15119 alc_codec_rename(codec, "ALC269VB");
15120 spec->codec_variant = ALC269_TYPE_ALC269VB;
15121 }
15122 } else
15123 alc_fix_pll_init(codec, 0x20, 0x04, 15);
15124 alc269_fill_coef(codec);
15125 }
Kailang Yang977ddd62010-09-15 10:02:29 +020015126
Kailang Yangf6a92242007-12-13 16:52:54 +010015127 board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST,
15128 alc269_models,
15129 alc269_cfg_tbl);
15130
15131 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020015132 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
15133 codec->chip_name);
Kailang Yangf6a92242007-12-13 16:52:54 +010015134 board_config = ALC269_AUTO;
15135 }
15136
Takashi Iwaiff818c22010-04-12 08:59:25 +020015137 if (board_config == ALC269_AUTO)
15138 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1);
15139
Kailang Yangf6a92242007-12-13 16:52:54 +010015140 if (board_config == ALC269_AUTO) {
15141 /* automatic parse from the BIOS config */
15142 err = alc269_parse_auto_config(codec);
15143 if (err < 0) {
15144 alc_free(codec);
15145 return err;
15146 } else if (!err) {
15147 printk(KERN_INFO
15148 "hda_codec: Cannot set up configuration "
15149 "from BIOS. Using base mode...\n");
15150 board_config = ALC269_BASIC;
15151 }
15152 }
15153
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015154 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020015155 err = snd_hda_attach_beep_device(codec, 0x1);
15156 if (err < 0) {
15157 alc_free(codec);
15158 return err;
15159 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090015160 }
15161
Kailang Yangf6a92242007-12-13 16:52:54 +010015162 if (board_config != ALC269_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020015163 setup_preset(codec, &alc269_presets[board_config]);
Kailang Yangf6a92242007-12-13 16:52:54 +010015164
Kailang Yang84898e82010-02-04 14:16:14 +010015165 if (board_config == ALC269_QUANTA_FL1) {
Takashi Iwaif03d3112009-03-05 14:18:16 +010015166 /* Due to a hardware problem on Lenovo Ideadpad, we need to
15167 * fix the sample rate of analog I/O to 44.1kHz
15168 */
15169 spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
15170 spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
Takashi Iwai840b64c2010-07-13 22:49:01 +020015171 } else if (spec->dual_adc_switch) {
15172 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15173 /* switch ADC dynamically */
15174 spec->stream_analog_capture = &dualmic_pcm_analog_capture;
Takashi Iwaif03d3112009-03-05 14:18:16 +010015175 } else {
15176 spec->stream_analog_playback = &alc269_pcm_analog_playback;
15177 spec->stream_analog_capture = &alc269_pcm_analog_capture;
15178 }
Kailang Yangf6a92242007-12-13 16:52:54 +010015179 spec->stream_digital_playback = &alc269_pcm_digital_playback;
15180 spec->stream_digital_capture = &alc269_pcm_digital_capture;
15181
Takashi Iwai66946352010-03-29 17:21:45 +020015182 if (!spec->adc_nids) { /* wasn't filled automatically? use default */
Kailang Yang1657cbd2010-11-23 08:53:32 +010015183 if (spec->codec_variant == ALC269_TYPE_NORMAL) {
Takashi Iwai66946352010-03-29 17:21:45 +020015184 spec->adc_nids = alc269_adc_nids;
15185 spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
15186 spec->capsrc_nids = alc269_capsrc_nids;
15187 } else {
15188 spec->adc_nids = alc269vb_adc_nids;
15189 spec->num_adc_nids = ARRAY_SIZE(alc269vb_adc_nids);
15190 spec->capsrc_nids = alc269vb_capsrc_nids;
15191 }
Kailang Yang84898e82010-02-04 14:16:14 +010015192 }
15193
Takashi Iwaif9e336f2008-10-31 16:37:07 +010015194 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020015195 set_capture_mixer(codec);
Takashi Iwaidc1eae22010-07-29 15:30:02 +020015196 if (has_cdefine_beep(codec))
Kailang Yangda00c242010-03-19 11:23:45 +010015197 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
Kailang Yangf6a92242007-12-13 16:52:54 +010015198
Takashi Iwaiff818c22010-04-12 08:59:25 +020015199 if (board_config == ALC269_AUTO)
15200 alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0);
15201
Takashi Iwai100d5eb2009-08-10 11:55:51 +020015202 spec->vmaster_nid = 0x02;
15203
Kailang Yangf6a92242007-12-13 16:52:54 +010015204 codec->patch_ops = alc_patch_ops;
Kailang Yang977ddd62010-09-15 10:02:29 +020015205#ifdef CONFIG_SND_HDA_POWER_SAVE
15206 codec->patch_ops.suspend = alc269_suspend;
15207#endif
15208#ifdef SND_HDA_NEEDS_RESUME
15209 codec->patch_ops.resume = alc269_resume;
15210#endif
Kailang Yangf6a92242007-12-13 16:52:54 +010015211 if (board_config == ALC269_AUTO)
15212 spec->init_hook = alc269_auto_init;
Kailang Yangbf1b0222010-10-21 08:49:56 +020015213
15214 alc_init_jacks(codec);
Kailang Yangf6a92242007-12-13 16:52:54 +010015215#ifdef CONFIG_SND_HDA_POWER_SAVE
15216 if (!spec->loopback.amplist)
15217 spec->loopback.amplist = alc269_loopbacks;
Takashi Iwaiad358792010-03-30 18:00:59 +020015218 if (alc269_mic2_for_mute_led(codec))
15219 codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
Kailang Yangf6a92242007-12-13 16:52:54 +010015220#endif
15221
15222 return 0;
15223}
15224
15225/*
Kailang Yangdf694da2005-12-05 19:42:22 +010015226 * ALC861 channel source setting (2/6 channel selection for 3-stack)
15227 */
15228
15229/*
15230 * set the path ways for 2 channel output
15231 * need to set the codec line out and mic 1 pin widgets to inputs
15232 */
15233static struct hda_verb alc861_threestack_ch2_init[] = {
15234 /* set pin widget 1Ah (line in) for input */
15235 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015236 /* set pin widget 18h (mic1/2) for input, for mic also enable
15237 * the vref
15238 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015239 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15240
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015241 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15242#if 0
15243 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15244 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15245#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015246 { } /* end */
15247};
15248/*
15249 * 6ch mode
15250 * need to set the codec line out and mic 1 pin widgets to outputs
15251 */
15252static struct hda_verb alc861_threestack_ch6_init[] = {
15253 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15254 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15255 /* set pin widget 18h (mic1) for output (CLFE)*/
15256 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15257
15258 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015259 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015260
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015261 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15262#if 0
15263 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15264 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15265#endif
Kailang Yangdf694da2005-12-05 19:42:22 +010015266 { } /* end */
15267};
15268
15269static struct hda_channel_mode alc861_threestack_modes[2] = {
15270 { 2, alc861_threestack_ch2_init },
15271 { 6, alc861_threestack_ch6_init },
15272};
Takashi Iwai22309c32006-08-09 16:57:28 +020015273/* Set mic1 as input and unmute the mixer */
15274static struct hda_verb alc861_uniwill_m31_ch2_init[] = {
15275 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15276 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15277 { } /* end */
15278};
15279/* Set mic1 as output and mute mixer */
15280static struct hda_verb alc861_uniwill_m31_ch4_init[] = {
15281 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15282 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15283 { } /* end */
15284};
15285
15286static struct hda_channel_mode alc861_uniwill_m31_modes[2] = {
15287 { 2, alc861_uniwill_m31_ch2_init },
15288 { 4, alc861_uniwill_m31_ch4_init },
15289};
Kailang Yangdf694da2005-12-05 19:42:22 +010015290
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015291/* Set mic1 and line-in as input and unmute the mixer */
15292static struct hda_verb alc861_asus_ch2_init[] = {
15293 /* set pin widget 1Ah (line in) for input */
15294 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015295 /* set pin widget 18h (mic1/2) for input, for mic also enable
15296 * the vref
15297 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015298 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15299
15300 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
15301#if 0
15302 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
15303 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
15304#endif
15305 { } /* end */
15306};
15307/* Set mic1 nad line-in as output and mute mixer */
15308static struct hda_verb alc861_asus_ch6_init[] = {
15309 /* set pin widget 1Ah (line in) for output (Back Surround)*/
15310 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15311 /* { 0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15312 /* set pin widget 18h (mic1) for output (CLFE)*/
15313 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15314 /* { 0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, */
15315 { 0x0c, AC_VERB_SET_CONNECT_SEL, 0x00 },
15316 { 0x0d, AC_VERB_SET_CONNECT_SEL, 0x00 },
15317
15318 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
15319#if 0
15320 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8)) }, /*mic*/
15321 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8)) }, /*line in*/
15322#endif
15323 { } /* end */
15324};
15325
15326static struct hda_channel_mode alc861_asus_modes[2] = {
15327 { 2, alc861_asus_ch2_init },
15328 { 6, alc861_asus_ch6_init },
15329};
15330
Kailang Yangdf694da2005-12-05 19:42:22 +010015331/* patch-ALC861 */
15332
15333static struct snd_kcontrol_new alc861_base_mixer[] = {
15334 /* output mixer control */
15335 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15336 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15337 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15338 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15339 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15340
15341 /*Input mixer control */
15342 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15343 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15344 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15345 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15346 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15347 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15348 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15349 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15350 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15351 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015352
Kailang Yangdf694da2005-12-05 19:42:22 +010015353 { } /* end */
15354};
15355
15356static struct snd_kcontrol_new alc861_3ST_mixer[] = {
15357 /* output mixer control */
15358 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15359 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15360 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15361 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15362 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15363
15364 /* Input mixer control */
15365 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15366 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15367 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15368 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15369 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15370 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15371 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15372 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15373 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15374 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015375
Kailang Yangdf694da2005-12-05 19:42:22 +010015376 {
15377 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15378 .name = "Channel Mode",
15379 .info = alc_ch_mode_info,
15380 .get = alc_ch_mode_get,
15381 .put = alc_ch_mode_put,
15382 .private_value = ARRAY_SIZE(alc861_threestack_modes),
15383 },
15384 { } /* end */
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015385};
15386
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015387static struct snd_kcontrol_new alc861_toshiba_mixer[] = {
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015388 /* output mixer control */
15389 HDA_CODEC_MUTE("Master Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15390 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15391 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020015392
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015393 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015394};
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015395
Takashi Iwai22309c32006-08-09 16:57:28 +020015396static struct snd_kcontrol_new alc861_uniwill_m31_mixer[] = {
15397 /* output mixer control */
15398 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15399 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15400 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15401 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15402 /*HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT), */
15403
15404 /* Input mixer control */
15405 /* HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15406 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT), */
15407 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15408 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15409 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15410 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15411 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15412 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15413 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
15414 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_INPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015415
Takashi Iwai22309c32006-08-09 16:57:28 +020015416 {
15417 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15418 .name = "Channel Mode",
15419 .info = alc_ch_mode_info,
15420 .get = alc_ch_mode_get,
15421 .put = alc_ch_mode_put,
15422 .private_value = ARRAY_SIZE(alc861_uniwill_m31_modes),
15423 },
15424 { } /* end */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015425};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015426
15427static struct snd_kcontrol_new alc861_asus_mixer[] = {
15428 /* output mixer control */
15429 HDA_CODEC_MUTE("Front Playback Switch", 0x03, 0x0, HDA_OUTPUT),
15430 HDA_CODEC_MUTE("Surround Playback Switch", 0x06, 0x0, HDA_OUTPUT),
15431 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT),
15432 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT),
15433 HDA_CODEC_MUTE("Side Playback Switch", 0x04, 0x0, HDA_OUTPUT),
15434
15435 /* Input mixer control */
15436 HDA_CODEC_VOLUME("Input Playback Volume", 0x15, 0x0, HDA_OUTPUT),
15437 HDA_CODEC_MUTE("Input Playback Switch", 0x15, 0x0, HDA_OUTPUT),
15438 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15439 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
15440 HDA_CODEC_VOLUME("Line Playback Volume", 0x15, 0x02, HDA_INPUT),
15441 HDA_CODEC_MUTE("Line Playback Switch", 0x15, 0x02, HDA_INPUT),
15442 HDA_CODEC_VOLUME("Mic Playback Volume", 0x15, 0x01, HDA_INPUT),
15443 HDA_CODEC_MUTE("Mic Playback Switch", 0x15, 0x01, HDA_INPUT),
15444 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x10, 0x01, HDA_OUTPUT),
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015445 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x03, HDA_OUTPUT),
15446
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015447 {
15448 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
15449 .name = "Channel Mode",
15450 .info = alc_ch_mode_info,
15451 .get = alc_ch_mode_get,
15452 .put = alc_ch_mode_put,
15453 .private_value = ARRAY_SIZE(alc861_asus_modes),
15454 },
15455 { }
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015456};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015457
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015458/* additional mixer */
Takashi Iwaid1d985f2006-11-23 19:27:12 +010015459static struct snd_kcontrol_new alc861_asus_laptop_mixer[] = {
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015460 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_INPUT),
15461 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_INPUT),
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015462 { }
15463};
15464
Kailang Yangdf694da2005-12-05 19:42:22 +010015465/*
15466 * generic initialization of ADC, input mixers and output mixers
15467 */
15468static struct hda_verb alc861_base_init_verbs[] = {
15469 /*
15470 * Unmute ADC0 and set the default input to mic-in
15471 */
15472 /* port-A for surround (rear panel) */
15473 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15474 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x00 },
15475 /* port-B for mic-in (rear panel) with vref */
15476 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15477 /* port-C for line-in (rear panel) */
15478 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15479 /* port-D for Front */
15480 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15481 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15482 /* port-E for HP out (front panel) */
15483 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15484 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015485 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015486 /* port-F for mic-in (front panel) with vref */
15487 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15488 /* port-G for CLFE (rear panel) */
15489 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15490 { 0x1f, AC_VERB_SET_CONNECT_SEL, 0x00 },
15491 /* port-H for side (rear panel) */
15492 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15493 { 0x20, AC_VERB_SET_CONNECT_SEL, 0x00 },
15494 /* CD-in */
15495 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15496 /* route front mic to ADC1*/
15497 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15498 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015499
Kailang Yangdf694da2005-12-05 19:42:22 +010015500 /* Unmute DAC0~3 & spdif out*/
15501 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15502 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15503 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15504 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15505 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015506
Kailang Yangdf694da2005-12-05 19:42:22 +010015507 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15508 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15509 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15510 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15511 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015512
Kailang Yangdf694da2005-12-05 19:42:22 +010015513 /* Unmute Stereo Mixer 15 */
15514 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15515 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15516 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015517 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015518
15519 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15520 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15521 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15522 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15523 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15524 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15525 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15526 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015527 /* hp used DAC 3 (Front) */
15528 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015529 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15530
15531 { }
15532};
15533
15534static struct hda_verb alc861_threestack_init_verbs[] = {
15535 /*
15536 * Unmute ADC0 and set the default input to mic-in
15537 */
15538 /* port-A for surround (rear panel) */
15539 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15540 /* port-B for mic-in (rear panel) with vref */
15541 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15542 /* port-C for line-in (rear panel) */
15543 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15544 /* port-D for Front */
15545 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15546 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15547 /* port-E for HP out (front panel) */
15548 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
15549 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015550 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Kailang Yangdf694da2005-12-05 19:42:22 +010015551 /* port-F for mic-in (front panel) with vref */
15552 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15553 /* port-G for CLFE (rear panel) */
15554 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15555 /* port-H for side (rear panel) */
15556 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15557 /* CD-in */
15558 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15559 /* route front mic to ADC1*/
15560 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15561 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15562 /* Unmute DAC0~3 & spdif out*/
15563 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15564 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15565 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15566 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15567 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015568
Kailang Yangdf694da2005-12-05 19:42:22 +010015569 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15570 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15571 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15572 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15573 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015574
Kailang Yangdf694da2005-12-05 19:42:22 +010015575 /* Unmute Stereo Mixer 15 */
15576 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15577 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15578 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015579 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Kailang Yangdf694da2005-12-05 19:42:22 +010015580
15581 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15582 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15583 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15584 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15585 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15586 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15587 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15588 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015589 /* hp used DAC 3 (Front) */
15590 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015591 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15592 { }
15593};
Takashi Iwai22309c32006-08-09 16:57:28 +020015594
15595static struct hda_verb alc861_uniwill_m31_init_verbs[] = {
15596 /*
15597 * Unmute ADC0 and set the default input to mic-in
15598 */
15599 /* port-A for surround (rear panel) */
15600 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15601 /* port-B for mic-in (rear panel) with vref */
15602 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15603 /* port-C for line-in (rear panel) */
15604 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15605 /* port-D for Front */
15606 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15607 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15608 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015609 /* this has to be set to VREF80 */
15610 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015611 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015612 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Takashi Iwai22309c32006-08-09 16:57:28 +020015613 /* port-F for mic-in (front panel) with vref */
15614 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15615 /* port-G for CLFE (rear panel) */
15616 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15617 /* port-H for side (rear panel) */
15618 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
15619 /* CD-in */
15620 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15621 /* route front mic to ADC1*/
15622 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15623 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15624 /* Unmute DAC0~3 & spdif out*/
15625 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15626 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15627 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15628 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15629 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015630
Takashi Iwai22309c32006-08-09 16:57:28 +020015631 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15632 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15633 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15634 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15635 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015636
Takashi Iwai22309c32006-08-09 16:57:28 +020015637 /* Unmute Stereo Mixer 15 */
15638 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15639 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15640 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015641 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Takashi Iwai22309c32006-08-09 16:57:28 +020015642
15643 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15644 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15645 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15646 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15647 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15648 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15649 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15650 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015651 /* hp used DAC 3 (Front) */
15652 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Takashi Iwai22309c32006-08-09 16:57:28 +020015653 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15654 { }
15655};
15656
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015657static struct hda_verb alc861_asus_init_verbs[] = {
15658 /*
15659 * Unmute ADC0 and set the default input to mic-in
15660 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015661 /* port-A for surround (rear panel)
15662 * according to codec#0 this is the HP jack
15663 */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015664 { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, /* was 0x00 */
15665 /* route front PCM to HP */
15666 { 0x0e, AC_VERB_SET_CONNECT_SEL, 0x01 },
15667 /* port-B for mic-in (rear panel) with vref */
15668 { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15669 /* port-C for line-in (rear panel) */
15670 { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15671 /* port-D for Front */
15672 { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15673 { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x00 },
15674 /* port-E for HP out (front panel) */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015675 /* this has to be set to VREF80 */
15676 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015677 /* route front PCM to HP */
Takashi Iwai9dece1d2006-11-16 17:12:49 +010015678 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015679 /* port-F for mic-in (front panel) with vref */
15680 { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
15681 /* port-G for CLFE (rear panel) */
15682 { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15683 /* port-H for side (rear panel) */
15684 { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
15685 /* CD-in */
15686 { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
15687 /* route front mic to ADC1*/
15688 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00},
15689 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15690 /* Unmute DAC0~3 & spdif out*/
15691 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15692 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15693 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15694 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15695 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
15696 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15697 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15698 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15699 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15700 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015701
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015702 /* Unmute Stereo Mixer 15 */
15703 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15704 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15705 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015706 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c}, /* Output 0~12 step */
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015707
15708 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15709 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15710 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15711 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15712 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15713 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15714 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15715 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015716 /* hp used DAC 3 (Front) */
15717 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015718 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15719 { }
15720};
15721
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010015722/* additional init verbs for ASUS laptops */
15723static struct hda_verb alc861_asus_laptop_init_verbs[] = {
15724 { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x45 }, /* HP-out */
15725 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2) }, /* mute line-in */
15726 { }
15727};
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020015728
Kailang Yangdf694da2005-12-05 19:42:22 +010015729/*
15730 * generic initialization of ADC, input mixers and output mixers
15731 */
15732static struct hda_verb alc861_auto_init_verbs[] = {
15733 /*
15734 * Unmute ADC0 and set the default input to mic-in
15735 */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015736 /* {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, */
Kailang Yangdf694da2005-12-05 19:42:22 +010015737 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015738
Kailang Yangdf694da2005-12-05 19:42:22 +010015739 /* Unmute DAC0~3 & spdif out*/
15740 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15741 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15742 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15743 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
15744 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangea1fb292008-08-26 12:58:38 +020015745
Kailang Yangdf694da2005-12-05 19:42:22 +010015746 /* Unmute Mixer 14 (mic) 1c (Line in)*/
15747 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15748 {0x014, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15749 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15750 {0x01c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020015751
Kailang Yangdf694da2005-12-05 19:42:22 +010015752 /* Unmute Stereo Mixer 15 */
15753 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
15754 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
15755 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
15756 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c},
15757
Takashi Iwai1c209302009-07-22 15:17:45 +020015758 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15759 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15760 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15761 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15762 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15763 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
15764 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15765 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015766
15767 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15768 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015769 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15770 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015771 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
15772 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwai1c209302009-07-22 15:17:45 +020015773 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
15774 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
Kailang Yangdf694da2005-12-05 19:42:22 +010015775
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015776 {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, /* set Mic 1 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015777
15778 { }
15779};
15780
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015781static struct hda_verb alc861_toshiba_init_verbs[] = {
15782 {0x0f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015783
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015784 { }
15785};
15786
15787/* toggle speaker-output according to the hp-jack state */
15788static void alc861_toshiba_automute(struct hda_codec *codec)
15789{
Wu Fengguang864f92b2009-11-18 12:38:02 +080015790 unsigned int present = snd_hda_jack_detect(codec, 0x0f);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015791
Takashi Iwai47fd8302007-08-10 17:11:07 +020015792 snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0,
15793 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
15794 snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3,
15795 HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE);
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015796}
15797
15798static void alc861_toshiba_unsol_event(struct hda_codec *codec,
15799 unsigned int res)
15800{
Tobin Davisa53d1ae2006-10-17 12:00:28 +020015801 if ((res >> 26) == ALC880_HP_EVENT)
15802 alc861_toshiba_automute(codec);
15803}
15804
Sasha Alexandrdef319f2009-06-16 16:00:15 -040015805/* pcm configuration: identical with ALC880 */
Kailang Yangdf694da2005-12-05 19:42:22 +010015806#define alc861_pcm_analog_playback alc880_pcm_analog_playback
15807#define alc861_pcm_analog_capture alc880_pcm_analog_capture
15808#define alc861_pcm_digital_playback alc880_pcm_digital_playback
15809#define alc861_pcm_digital_capture alc880_pcm_digital_capture
15810
15811
15812#define ALC861_DIGOUT_NID 0x07
15813
15814static struct hda_channel_mode alc861_8ch_modes[1] = {
15815 { 8, NULL }
15816};
15817
15818static hda_nid_t alc861_dac_nids[4] = {
15819 /* front, surround, clfe, side */
15820 0x03, 0x06, 0x05, 0x04
15821};
15822
Takashi Iwai9c7f8522006-06-28 15:08:22 +020015823static hda_nid_t alc660_dac_nids[3] = {
15824 /* front, clfe, surround */
15825 0x03, 0x05, 0x06
15826};
15827
Kailang Yangdf694da2005-12-05 19:42:22 +010015828static hda_nid_t alc861_adc_nids[1] = {
15829 /* ADC0-2 */
15830 0x08,
15831};
15832
15833static struct hda_input_mux alc861_capture_source = {
15834 .num_items = 5,
15835 .items = {
15836 { "Mic", 0x0 },
15837 { "Front Mic", 0x3 },
15838 { "Line", 0x1 },
15839 { "CD", 0x4 },
15840 { "Mixer", 0x5 },
15841 },
15842};
15843
Takashi Iwai1c209302009-07-22 15:17:45 +020015844static hda_nid_t alc861_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
15845{
15846 struct alc_spec *spec = codec->spec;
15847 hda_nid_t mix, srcs[5];
15848 int i, j, num;
15849
15850 if (snd_hda_get_connections(codec, pin, &mix, 1) != 1)
15851 return 0;
15852 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15853 if (num < 0)
15854 return 0;
15855 for (i = 0; i < num; i++) {
15856 unsigned int type;
Takashi Iwaia22d5432009-07-27 12:54:26 +020015857 type = get_wcaps_type(get_wcaps(codec, srcs[i]));
Takashi Iwai1c209302009-07-22 15:17:45 +020015858 if (type != AC_WID_AUD_OUT)
15859 continue;
15860 for (j = 0; j < spec->multiout.num_dacs; j++)
15861 if (spec->multiout.dac_nids[j] == srcs[i])
15862 break;
15863 if (j >= spec->multiout.num_dacs)
15864 return srcs[i];
15865 }
15866 return 0;
15867}
15868
Kailang Yangdf694da2005-12-05 19:42:22 +010015869/* fill in the dac_nids table from the parsed pin configuration */
Takashi Iwai1c209302009-07-22 15:17:45 +020015870static int alc861_auto_fill_dac_nids(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015871 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015872{
Takashi Iwai1c209302009-07-22 15:17:45 +020015873 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015874 int i;
Takashi Iwai1c209302009-07-22 15:17:45 +020015875 hda_nid_t nid, dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015876
15877 spec->multiout.dac_nids = spec->private_dac_nids;
15878 for (i = 0; i < cfg->line_outs; i++) {
15879 nid = cfg->line_out_pins[i];
Takashi Iwai1c209302009-07-22 15:17:45 +020015880 dac = alc861_look_for_dac(codec, nid);
15881 if (!dac)
15882 continue;
15883 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
Kailang Yangdf694da2005-12-05 19:42:22 +010015884 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015885 return 0;
15886}
15887
Takashi Iwai1c209302009-07-22 15:17:45 +020015888static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx,
15889 hda_nid_t nid, unsigned int chs)
Kailang Yangdf694da2005-12-05 19:42:22 +010015890{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020015891 return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai1c209302009-07-22 15:17:45 +020015892 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
15893}
15894
15895/* add playback controls from the parsed DAC table */
15896static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec,
15897 const struct auto_pin_cfg *cfg)
15898{
15899 struct alc_spec *spec = codec->spec;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015900 static const char *chname[4] = {
15901 "Front", "Surround", NULL /*CLFE*/, "Side"
15902 };
Kailang Yangdf694da2005-12-05 19:42:22 +010015903 hda_nid_t nid;
Takashi Iwai1c209302009-07-22 15:17:45 +020015904 int i, err;
15905
15906 if (cfg->line_outs == 1) {
15907 const char *pfx = NULL;
15908 if (!cfg->hp_outs)
15909 pfx = "Master";
15910 else if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
15911 pfx = "Speaker";
15912 if (pfx) {
15913 nid = spec->multiout.dac_nids[0];
15914 return alc861_create_out_sw(codec, pfx, nid, 3);
15915 }
15916 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015917
15918 for (i = 0; i < cfg->line_outs; i++) {
15919 nid = spec->multiout.dac_nids[i];
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015920 if (!nid)
Kailang Yangdf694da2005-12-05 19:42:22 +010015921 continue;
Takashi Iwai1c209302009-07-22 15:17:45 +020015922 if (i == 2) {
Kailang Yangdf694da2005-12-05 19:42:22 +010015923 /* Center/LFE */
Takashi Iwai1c209302009-07-22 15:17:45 +020015924 err = alc861_create_out_sw(codec, "Center", nid, 1);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015925 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015926 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020015927 err = alc861_create_out_sw(codec, "LFE", nid, 2);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015928 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015929 return err;
15930 } else {
Takashi Iwai1c209302009-07-22 15:17:45 +020015931 err = alc861_create_out_sw(codec, chname[i], nid, 3);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015932 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010015933 return err;
15934 }
15935 }
15936 return 0;
15937}
15938
Takashi Iwai1c209302009-07-22 15:17:45 +020015939static int alc861_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015940{
Takashi Iwai1c209302009-07-22 15:17:45 +020015941 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010015942 int err;
15943 hda_nid_t nid;
15944
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015945 if (!pin)
Kailang Yangdf694da2005-12-05 19:42:22 +010015946 return 0;
15947
15948 if ((pin >= 0x0b && pin <= 0x10) || pin == 0x1f || pin == 0x20) {
Takashi Iwai1c209302009-07-22 15:17:45 +020015949 nid = alc861_look_for_dac(codec, pin);
15950 if (nid) {
15951 err = alc861_create_out_sw(codec, "Headphone", nid, 3);
15952 if (err < 0)
15953 return err;
15954 spec->multiout.hp_nid = nid;
15955 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015956 }
15957 return 0;
15958}
15959
15960/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020015961static int alc861_auto_create_input_ctls(struct hda_codec *codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015962 const struct auto_pin_cfg *cfg)
Kailang Yangdf694da2005-12-05 19:42:22 +010015963{
Takashi Iwai05f5f472009-08-25 13:10:18 +020015964 return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x08, 0);
Kailang Yangdf694da2005-12-05 19:42:22 +010015965}
15966
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020015967static void alc861_auto_set_output_and_unmute(struct hda_codec *codec,
15968 hda_nid_t nid,
Takashi Iwai1c209302009-07-22 15:17:45 +020015969 int pin_type, hda_nid_t dac)
Kailang Yangdf694da2005-12-05 19:42:22 +010015970{
Takashi Iwai1c209302009-07-22 15:17:45 +020015971 hda_nid_t mix, srcs[5];
15972 int i, num;
15973
Jacek Luczak564c5be2008-05-03 18:41:23 +020015974 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
15975 pin_type);
Takashi Iwai1c209302009-07-22 15:17:45 +020015976 snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
Jacek Luczak564c5be2008-05-03 18:41:23 +020015977 AMP_OUT_UNMUTE);
Takashi Iwai1c209302009-07-22 15:17:45 +020015978 if (snd_hda_get_connections(codec, nid, &mix, 1) != 1)
15979 return;
15980 num = snd_hda_get_connections(codec, mix, srcs, ARRAY_SIZE(srcs));
15981 if (num < 0)
15982 return;
15983 for (i = 0; i < num; i++) {
15984 unsigned int mute;
15985 if (srcs[i] == dac || srcs[i] == 0x15)
15986 mute = AMP_IN_UNMUTE(i);
15987 else
15988 mute = AMP_IN_MUTE(i);
15989 snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
15990 mute);
15991 }
Kailang Yangdf694da2005-12-05 19:42:22 +010015992}
15993
15994static void alc861_auto_init_multi_out(struct hda_codec *codec)
15995{
15996 struct alc_spec *spec = codec->spec;
15997 int i;
15998
15999 for (i = 0; i < spec->autocfg.line_outs; i++) {
16000 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016001 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016002 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016003 alc861_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016004 spec->multiout.dac_nids[i]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016005 }
16006}
16007
16008static void alc861_auto_init_hp_out(struct hda_codec *codec)
16009{
16010 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016011
Takashi Iwai15870f02009-10-05 08:25:13 +020016012 if (spec->autocfg.hp_outs)
16013 alc861_auto_set_output_and_unmute(codec,
16014 spec->autocfg.hp_pins[0],
16015 PIN_HP,
Takashi Iwai1c209302009-07-22 15:17:45 +020016016 spec->multiout.hp_nid);
Takashi Iwai15870f02009-10-05 08:25:13 +020016017 if (spec->autocfg.speaker_outs)
16018 alc861_auto_set_output_and_unmute(codec,
16019 spec->autocfg.speaker_pins[0],
16020 PIN_OUT,
Takashi Iwai1c209302009-07-22 15:17:45 +020016021 spec->multiout.dac_nids[0]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016022}
16023
16024static void alc861_auto_init_analog_input(struct hda_codec *codec)
16025{
16026 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016027 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangdf694da2005-12-05 19:42:22 +010016028 int i;
16029
Takashi Iwai66ceeb62010-08-30 13:05:52 +020016030 for (i = 0; i < cfg->num_inputs; i++) {
16031 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai23f0c042009-02-26 13:03:58 +010016032 if (nid >= 0x0c && nid <= 0x11)
Takashi Iwai30ea0982010-09-16 18:47:56 +020016033 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Kailang Yangdf694da2005-12-05 19:42:22 +010016034 }
16035}
16036
16037/* parse the BIOS configuration and set up the alc_spec */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016038/* return 1 if successful, 0 if the proper config is not found,
16039 * or a negative error code
16040 */
Kailang Yangdf694da2005-12-05 19:42:22 +010016041static int alc861_parse_auto_config(struct hda_codec *codec)
16042{
16043 struct alc_spec *spec = codec->spec;
16044 int err;
16045 static hda_nid_t alc861_ignore[] = { 0x1d, 0 };
16046
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016047 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
16048 alc861_ignore);
16049 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016050 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016051 if (!spec->autocfg.line_outs)
Kailang Yangdf694da2005-12-05 19:42:22 +010016052 return 0; /* can't find valid BIOS pin config */
16053
Takashi Iwai1c209302009-07-22 15:17:45 +020016054 err = alc861_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016055 if (err < 0)
16056 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016057 err = alc861_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016058 if (err < 0)
16059 return err;
Takashi Iwai1c209302009-07-22 15:17:45 +020016060 err = alc861_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016061 if (err < 0)
16062 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020016063 err = alc861_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016064 if (err < 0)
Kailang Yangdf694da2005-12-05 19:42:22 +010016065 return err;
16066
16067 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
16068
Takashi Iwai757899a2010-07-30 10:48:14 +020016069 alc_auto_parse_digital(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016070
Takashi Iwai603c4012008-07-30 15:01:44 +020016071 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010016072 add_mixer(spec, spec->kctls.list);
Kailang Yangdf694da2005-12-05 19:42:22 +010016073
Takashi Iwaid88897e2008-10-31 15:01:37 +010016074 add_verb(spec, alc861_auto_init_verbs);
Kailang Yangdf694da2005-12-05 19:42:22 +010016075
Jonathan Woithea1e8d2d2006-03-28 12:47:09 +020016076 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020016077 spec->input_mux = &spec->private_imux[0];
Kailang Yangdf694da2005-12-05 19:42:22 +010016078
16079 spec->adc_nids = alc861_adc_nids;
16080 spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids);
Takashi Iwaib59bdf32009-08-11 09:47:30 +020016081 set_capture_mixer(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016082
Kailang Yang6227cdc2010-02-25 08:36:52 +010016083 alc_ssid_check(codec, 0x0e, 0x0f, 0x0b, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020016084
Kailang Yangdf694da2005-12-05 19:42:22 +010016085 return 1;
16086}
16087
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016088/* additional initialization for auto-configuration model */
16089static void alc861_auto_init(struct hda_codec *codec)
Kailang Yangdf694da2005-12-05 19:42:22 +010016090{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016091 struct alc_spec *spec = codec->spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016092 alc861_auto_init_multi_out(codec);
16093 alc861_auto_init_hp_out(codec);
16094 alc861_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020016095 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016096 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020016097 alc_inithook(codec);
Kailang Yangdf694da2005-12-05 19:42:22 +010016098}
16099
Takashi Iwaicb53c622007-08-10 17:21:45 +020016100#ifdef CONFIG_SND_HDA_POWER_SAVE
16101static struct hda_amp_list alc861_loopbacks[] = {
16102 { 0x15, HDA_INPUT, 0 },
16103 { 0x15, HDA_INPUT, 1 },
16104 { 0x15, HDA_INPUT, 2 },
16105 { 0x15, HDA_INPUT, 3 },
16106 { } /* end */
16107};
16108#endif
16109
Kailang Yangdf694da2005-12-05 19:42:22 +010016110
16111/*
16112 * configuration and preset
16113 */
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016114static const char *alc861_models[ALC861_MODEL_LAST] = {
16115 [ALC861_3ST] = "3stack",
16116 [ALC660_3ST] = "3stack-660",
16117 [ALC861_3ST_DIG] = "3stack-dig",
16118 [ALC861_6ST_DIG] = "6stack-dig",
16119 [ALC861_UNIWILL_M31] = "uniwill-m31",
16120 [ALC861_TOSHIBA] = "toshiba",
16121 [ALC861_ASUS] = "asus",
16122 [ALC861_ASUS_LAPTOP] = "asus-laptop",
16123 [ALC861_AUTO] = "auto",
16124};
16125
16126static struct snd_pci_quirk alc861_cfg_tbl[] = {
Takashi Iwai687a47b2007-01-10 11:25:58 +010016127 SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC861_3ST),
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016128 SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16129 SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
16130 SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016131 SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
Kailang Yang83c34212007-07-05 11:43:05 +020016132 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
Tobin Davisad5e7732007-01-08 10:57:32 +010016133 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
Takashi Iwai341d4eb2007-07-09 17:53:18 +020016134 /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
16135 * Any other models that need this preset?
16136 */
16137 /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
Claudio Matsuokaef64adb2007-07-14 00:26:16 +020016138 SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
16139 SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016140 SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
16141 SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
16142 SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
16143 /* FIXME: the below seems conflict */
16144 /* SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31), */
16145 SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
16146 SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
Kailang Yangdf694da2005-12-05 19:42:22 +010016147 {}
16148};
16149
16150static struct alc_config_preset alc861_presets[] = {
16151 [ALC861_3ST] = {
16152 .mixers = { alc861_3ST_mixer },
16153 .init_verbs = { alc861_threestack_init_verbs },
16154 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16155 .dac_nids = alc861_dac_nids,
16156 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16157 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016158 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016159 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16160 .adc_nids = alc861_adc_nids,
16161 .input_mux = &alc861_capture_source,
16162 },
16163 [ALC861_3ST_DIG] = {
16164 .mixers = { alc861_base_mixer },
16165 .init_verbs = { alc861_threestack_init_verbs },
16166 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16167 .dac_nids = alc861_dac_nids,
16168 .dig_out_nid = ALC861_DIGOUT_NID,
16169 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16170 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016171 .need_dac_fix = 1,
Kailang Yangdf694da2005-12-05 19:42:22 +010016172 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16173 .adc_nids = alc861_adc_nids,
16174 .input_mux = &alc861_capture_source,
16175 },
16176 [ALC861_6ST_DIG] = {
16177 .mixers = { alc861_base_mixer },
16178 .init_verbs = { alc861_base_init_verbs },
16179 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16180 .dac_nids = alc861_dac_nids,
16181 .dig_out_nid = ALC861_DIGOUT_NID,
16182 .num_channel_mode = ARRAY_SIZE(alc861_8ch_modes),
16183 .channel_mode = alc861_8ch_modes,
16184 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16185 .adc_nids = alc861_adc_nids,
16186 .input_mux = &alc861_capture_source,
16187 },
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016188 [ALC660_3ST] = {
16189 .mixers = { alc861_3ST_mixer },
16190 .init_verbs = { alc861_threestack_init_verbs },
16191 .num_dacs = ARRAY_SIZE(alc660_dac_nids),
16192 .dac_nids = alc660_dac_nids,
16193 .num_channel_mode = ARRAY_SIZE(alc861_threestack_modes),
16194 .channel_mode = alc861_threestack_modes,
Takashi Iwai4e195a72006-07-28 14:47:34 +020016195 .need_dac_fix = 1,
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016196 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16197 .adc_nids = alc861_adc_nids,
16198 .input_mux = &alc861_capture_source,
16199 },
Takashi Iwai22309c32006-08-09 16:57:28 +020016200 [ALC861_UNIWILL_M31] = {
16201 .mixers = { alc861_uniwill_m31_mixer },
16202 .init_verbs = { alc861_uniwill_m31_init_verbs },
16203 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16204 .dac_nids = alc861_dac_nids,
16205 .dig_out_nid = ALC861_DIGOUT_NID,
16206 .num_channel_mode = ARRAY_SIZE(alc861_uniwill_m31_modes),
16207 .channel_mode = alc861_uniwill_m31_modes,
16208 .need_dac_fix = 1,
16209 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16210 .adc_nids = alc861_adc_nids,
16211 .input_mux = &alc861_capture_source,
16212 },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016213 [ALC861_TOSHIBA] = {
16214 .mixers = { alc861_toshiba_mixer },
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016215 .init_verbs = { alc861_base_init_verbs,
16216 alc861_toshiba_init_verbs },
Tobin Davisa53d1ae2006-10-17 12:00:28 +020016217 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16218 .dac_nids = alc861_dac_nids,
16219 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16220 .channel_mode = alc883_3ST_2ch_modes,
16221 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16222 .adc_nids = alc861_adc_nids,
16223 .input_mux = &alc861_capture_source,
16224 .unsol_event = alc861_toshiba_unsol_event,
16225 .init_hook = alc861_toshiba_automute,
16226 },
Mariusz Domanski7cdbff92006-10-23 13:42:56 +020016227 [ALC861_ASUS] = {
16228 .mixers = { alc861_asus_mixer },
16229 .init_verbs = { alc861_asus_init_verbs },
16230 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16231 .dac_nids = alc861_dac_nids,
16232 .dig_out_nid = ALC861_DIGOUT_NID,
16233 .num_channel_mode = ARRAY_SIZE(alc861_asus_modes),
16234 .channel_mode = alc861_asus_modes,
16235 .need_dac_fix = 1,
16236 .hp_nid = 0x06,
16237 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16238 .adc_nids = alc861_adc_nids,
16239 .input_mux = &alc861_capture_source,
16240 },
Takashi Iwai56bb0ca2006-11-22 11:52:52 +010016241 [ALC861_ASUS_LAPTOP] = {
16242 .mixers = { alc861_toshiba_mixer, alc861_asus_laptop_mixer },
16243 .init_verbs = { alc861_asus_init_verbs,
16244 alc861_asus_laptop_init_verbs },
16245 .num_dacs = ARRAY_SIZE(alc861_dac_nids),
16246 .dac_nids = alc861_dac_nids,
16247 .dig_out_nid = ALC861_DIGOUT_NID,
16248 .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
16249 .channel_mode = alc883_3ST_2ch_modes,
16250 .need_dac_fix = 1,
16251 .num_adc_nids = ARRAY_SIZE(alc861_adc_nids),
16252 .adc_nids = alc861_adc_nids,
16253 .input_mux = &alc861_capture_source,
16254 },
16255};
Kailang Yangdf694da2005-12-05 19:42:22 +010016256
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016257/* Pin config fixes */
16258enum {
16259 PINFIX_FSC_AMILO_PI1505,
16260};
16261
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016262static const struct alc_fixup alc861_fixups[] = {
16263 [PINFIX_FSC_AMILO_PI1505] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020016264 .pins = (const struct alc_pincfg[]) {
16265 { 0x0b, 0x0221101f }, /* HP */
16266 { 0x0f, 0x90170310 }, /* speaker */
16267 { }
16268 }
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016269 },
16270};
16271
16272static struct snd_pci_quirk alc861_fixup_tbl[] = {
16273 SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
16274 {}
16275};
Kailang Yangdf694da2005-12-05 19:42:22 +010016276
16277static int patch_alc861(struct hda_codec *codec)
16278{
16279 struct alc_spec *spec;
16280 int board_config;
16281 int err;
16282
Robert P. J. Daydc041e02006-12-19 14:44:15 +010016283 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
Kailang Yangdf694da2005-12-05 19:42:22 +010016284 if (spec == NULL)
16285 return -ENOMEM;
16286
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016287 codec->spec = spec;
Kailang Yangdf694da2005-12-05 19:42:22 +010016288
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016289 board_config = snd_hda_check_board_config(codec, ALC861_MODEL_LAST,
16290 alc861_models,
16291 alc861_cfg_tbl);
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016292
Takashi Iwaif5fcc132006-11-24 17:07:44 +010016293 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020016294 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
16295 codec->chip_name);
Kailang Yangdf694da2005-12-05 19:42:22 +010016296 board_config = ALC861_AUTO;
16297 }
16298
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016299 if (board_config == ALC861_AUTO)
16300 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1);
Takashi Iwaicfc9b062009-12-01 12:19:37 +010016301
Kailang Yangdf694da2005-12-05 19:42:22 +010016302 if (board_config == ALC861_AUTO) {
16303 /* automatic parse from the BIOS config */
16304 err = alc861_parse_auto_config(codec);
16305 if (err < 0) {
16306 alc_free(codec);
16307 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020016308 } else if (!err) {
Takashi Iwai9c7f8522006-06-28 15:08:22 +020016309 printk(KERN_INFO
16310 "hda_codec: Cannot set up configuration "
16311 "from BIOS. Using base mode...\n");
Kailang Yangdf694da2005-12-05 19:42:22 +010016312 board_config = ALC861_3ST_DIG;
16313 }
16314 }
16315
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090016316 err = snd_hda_attach_beep_device(codec, 0x23);
16317 if (err < 0) {
16318 alc_free(codec);
16319 return err;
16320 }
16321
Kailang Yangdf694da2005-12-05 19:42:22 +010016322 if (board_config != ALC861_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020016323 setup_preset(codec, &alc861_presets[board_config]);
Kailang Yangdf694da2005-12-05 19:42:22 +010016324
Kailang Yangdf694da2005-12-05 19:42:22 +010016325 spec->stream_analog_playback = &alc861_pcm_analog_playback;
16326 spec->stream_analog_capture = &alc861_pcm_analog_capture;
16327
Kailang Yangdf694da2005-12-05 19:42:22 +010016328 spec->stream_digital_playback = &alc861_pcm_digital_playback;
16329 spec->stream_digital_capture = &alc861_pcm_digital_capture;
16330
Takashi Iwaic7a8eb12010-01-14 12:39:02 +010016331 if (!spec->cap_mixer)
16332 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010016333 set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
16334
Takashi Iwai2134ea42008-01-10 16:53:55 +010016335 spec->vmaster_nid = 0x03;
16336
Takashi Iwai7fa90e82010-04-12 08:49:00 +020016337 if (board_config == ALC861_AUTO)
16338 alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0);
16339
Kailang Yangdf694da2005-12-05 19:42:22 +010016340 codec->patch_ops = alc_patch_ops;
Daniel T Chenc97259d2009-12-27 18:52:08 -050016341 if (board_config == ALC861_AUTO) {
Takashi Iwaiae6b8132006-03-03 16:47:17 +010016342 spec->init_hook = alc861_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020016343#ifdef CONFIG_SND_HDA_POWER_SAVE
Daniel T Chenc97259d2009-12-27 18:52:08 -050016344 spec->power_hook = alc_power_eapd;
16345#endif
16346 }
16347#ifdef CONFIG_SND_HDA_POWER_SAVE
Takashi Iwaicb53c622007-08-10 17:21:45 +020016348 if (!spec->loopback.amplist)
16349 spec->loopback.amplist = alc861_loopbacks;
16350#endif
Kailang Yangea1fb292008-08-26 12:58:38 +020016351
Kailang Yangdf694da2005-12-05 19:42:22 +010016352 return 0;
16353}
16354
16355/*
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016356 * ALC861-VD support
16357 *
16358 * Based on ALC882
16359 *
16360 * In addition, an independent DAC
16361 */
16362#define ALC861VD_DIGOUT_NID 0x06
16363
16364static hda_nid_t alc861vd_dac_nids[4] = {
16365 /* front, surr, clfe, side surr */
16366 0x02, 0x03, 0x04, 0x05
16367};
16368
16369/* dac_nids for ALC660vd are in a different order - according to
16370 * Realtek's driver.
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016371 * This should probably result in a different mixer for 6stack models
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016372 * of ALC660vd codecs, but for now there is only 3stack mixer
16373 * - and it is the same as in 861vd.
16374 * adc_nids in ALC660vd are (is) the same as in 861vd
16375 */
16376static hda_nid_t alc660vd_dac_nids[3] = {
16377 /* front, rear, clfe, rear_surr */
16378 0x02, 0x04, 0x03
16379};
16380
16381static hda_nid_t alc861vd_adc_nids[1] = {
16382 /* ADC0 */
16383 0x09,
16384};
16385
Takashi Iwaie1406342008-02-11 18:32:32 +010016386static hda_nid_t alc861vd_capsrc_nids[1] = { 0x22 };
16387
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016388/* input MUX */
16389/* FIXME: should be a matrix-type input source selection */
16390static struct hda_input_mux alc861vd_capture_source = {
16391 .num_items = 4,
16392 .items = {
16393 { "Mic", 0x0 },
16394 { "Front Mic", 0x1 },
16395 { "Line", 0x2 },
16396 { "CD", 0x4 },
16397 },
16398};
16399
Kailang Yang272a5272007-05-14 11:00:38 +020016400static struct hda_input_mux alc861vd_dallas_capture_source = {
Tobin Davisb419f342008-03-07 11:57:51 +010016401 .num_items = 2,
Kailang Yang272a5272007-05-14 11:00:38 +020016402 .items = {
David Henningsson8607f7c2010-12-20 14:43:54 +010016403 { "Mic", 0x0 },
David Henningsson28c4edb2010-12-20 14:24:29 +010016404 { "Internal Mic", 0x1 },
Kailang Yang272a5272007-05-14 11:00:38 +020016405 },
16406};
16407
Kailang Yangd1a991a2007-08-15 16:21:59 +020016408static struct hda_input_mux alc861vd_hp_capture_source = {
16409 .num_items = 2,
16410 .items = {
16411 { "Front Mic", 0x0 },
16412 { "ATAPI Mic", 0x1 },
16413 },
16414};
16415
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016416/*
16417 * 2ch mode
16418 */
16419static struct hda_channel_mode alc861vd_3stack_2ch_modes[1] = {
16420 { 2, NULL }
16421};
16422
16423/*
16424 * 6ch mode
16425 */
16426static struct hda_verb alc861vd_6stack_ch6_init[] = {
16427 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
16428 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16429 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16430 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16431 { } /* end */
16432};
16433
16434/*
16435 * 8ch mode
16436 */
16437static struct hda_verb alc861vd_6stack_ch8_init[] = {
16438 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16439 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16440 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16441 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
16442 { } /* end */
16443};
16444
16445static struct hda_channel_mode alc861vd_6stack_modes[2] = {
16446 { 6, alc861vd_6stack_ch6_init },
16447 { 8, alc861vd_6stack_ch8_init },
16448};
16449
16450static struct snd_kcontrol_new alc861vd_chmode_mixer[] = {
16451 {
16452 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
16453 .name = "Channel Mode",
16454 .info = alc_ch_mode_info,
16455 .get = alc_ch_mode_get,
16456 .put = alc_ch_mode_put,
16457 },
16458 { } /* end */
16459};
16460
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016461/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
16462 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
16463 */
16464static struct snd_kcontrol_new alc861vd_6st_mixer[] = {
16465 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16466 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16467
16468 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16469 HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT),
16470
16471 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0,
16472 HDA_OUTPUT),
16473 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0,
16474 HDA_OUTPUT),
16475 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
16476 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
16477
16478 HDA_CODEC_VOLUME("Side Playback Volume", 0x05, 0x0, HDA_OUTPUT),
16479 HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
16480
16481 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16482
David Henningsson5f99f862011-01-04 15:24:24 +010016483 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016484 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16485 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16486
David Henningsson5f99f862011-01-04 15:24:24 +010016487 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016488 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16489 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16490
16491 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16492 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16493
16494 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16495 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16496
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016497 { } /* end */
16498};
16499
16500static struct snd_kcontrol_new alc861vd_3st_mixer[] = {
16501 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16502 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16503
16504 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16505
David Henningsson5f99f862011-01-04 15:24:24 +010016506 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016507 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16508 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16509
David Henningsson5f99f862011-01-04 15:24:24 +010016510 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016511 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16512 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16513
16514 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
16515 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
16516
16517 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16518 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16519
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016520 { } /* end */
16521};
16522
Kailang Yangbdd148a2007-05-08 15:19:08 +020016523static struct snd_kcontrol_new alc861vd_lenovo_mixer[] = {
16524 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16525 /*HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),*/
16526 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
16527
16528 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
16529
David Henningsson5f99f862011-01-04 15:24:24 +010016530 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016531 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16532 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16533
David Henningsson5f99f862011-01-04 15:24:24 +010016534 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangbdd148a2007-05-08 15:19:08 +020016535 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16536 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
16537
16538 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
16539 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
16540
16541 { } /* end */
16542};
16543
Tobin Davisb419f342008-03-07 11:57:51 +010016544/* Pin assignment: Speaker=0x14, HP = 0x15,
David Henningsson8607f7c2010-12-20 14:43:54 +010016545 * Mic=0x18, Internal Mic = 0x19, CD = 0x1c, PC Beep = 0x1d
Kailang Yang272a5272007-05-14 11:00:38 +020016546 */
16547static struct snd_kcontrol_new alc861vd_dallas_mixer[] = {
Tobin Davisb419f342008-03-07 11:57:51 +010016548 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16549 HDA_BIND_MUTE("Speaker Playback Switch", 0x0c, 2, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016550 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16551 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016552 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson8607f7c2010-12-20 14:43:54 +010016553 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16554 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010016555 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson28c4edb2010-12-20 14:24:29 +010016556 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16557 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang272a5272007-05-14 11:00:38 +020016558 { } /* end */
16559};
16560
Kailang Yangd1a991a2007-08-15 16:21:59 +020016561/* Pin assignment: Speaker=0x14, Line-out = 0x15,
16562 * Front Mic=0x18, ATAPI Mic = 0x19,
16563 */
16564static struct snd_kcontrol_new alc861vd_hp_mixer[] = {
16565 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
16566 HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
16567 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
16568 HDA_BIND_MUTE("Headphone Playback Switch", 0x0d, 2, HDA_INPUT),
16569 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
16570 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
16571 HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
16572 HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangea1fb292008-08-26 12:58:38 +020016573
Kailang Yangd1a991a2007-08-15 16:21:59 +020016574 { } /* end */
16575};
16576
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016577/*
16578 * generic initialization of ADC, input mixers and output mixers
16579 */
16580static struct hda_verb alc861vd_volume_init_verbs[] = {
16581 /*
16582 * Unmute ADC0 and set the default input to mic-in
16583 */
16584 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
16585 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16586
16587 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of
16588 * the analog-loopback mixer widget
16589 */
16590 /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */
Takashi Iwaicb53c622007-08-10 17:21:45 +020016591 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16592 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16593 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16594 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16595 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016596
16597 /* Capture mixer: unmute Mic, F-Mic, Line, CD inputs */
Kailang Yangbdd148a2007-05-08 15:19:08 +020016598 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16599 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16600 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016601 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016602
16603 /*
16604 * Set up output mixers (0x02 - 0x05)
16605 */
16606 /* set vol=0 to output mixers */
16607 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16608 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16609 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16610 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16611
16612 /* set up input amps for analog loopback */
16613 /* Amp Indices: DAC = 0, mixer = 1 */
16614 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16615 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16616 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16617 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16618 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16619 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16620 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16621 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16622
16623 { }
16624};
16625
16626/*
16627 * 3-stack pin configuration:
16628 * front = 0x14, mic/clfe = 0x18, HP = 0x19, line/surr = 0x1a, f-mic = 0x1b
16629 */
16630static struct hda_verb alc861vd_3stack_init_verbs[] = {
16631 /*
16632 * Set pin mode and muting
16633 */
16634 /* set front pin widgets 0x14 for output */
16635 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16636 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16637 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16638
16639 /* Mic (rear) pin: input vref at 80% */
16640 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16641 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16642 /* Front Mic pin: input vref at 80% */
16643 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16644 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16645 /* Line In pin: input */
16646 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16647 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16648 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16649 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16650 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16651 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16652 /* CD pin widget for input */
16653 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16654
16655 { }
16656};
16657
16658/*
16659 * 6-stack pin configuration:
16660 */
16661static struct hda_verb alc861vd_6stack_init_verbs[] = {
16662 /*
16663 * Set pin mode and muting
16664 */
16665 /* set front pin widgets 0x14 for output */
16666 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16667 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16668 {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
16669
16670 /* Rear Pin: output 1 (0x0d) */
16671 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16672 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16673 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
16674 /* CLFE Pin: output 2 (0x0e) */
16675 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16676 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16677 {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},
16678 /* Side Pin: output 3 (0x0f) */
16679 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16680 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16681 {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},
16682
16683 /* Mic (rear) pin: input vref at 80% */
16684 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16685 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16686 /* Front Mic pin: input vref at 80% */
16687 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
16688 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16689 /* Line In pin: input */
16690 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16691 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16692 /* Line-2 In: Headphone output (output 0 - 0x0c) */
16693 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
16694 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16695 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
16696 /* CD pin widget for input */
16697 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16698
16699 { }
16700};
16701
Kailang Yangbdd148a2007-05-08 15:19:08 +020016702static struct hda_verb alc861vd_eapd_verbs[] = {
16703 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16704 { }
16705};
16706
Kailang Yangf9423e72008-05-27 12:32:25 +020016707static struct hda_verb alc660vd_eapd_verbs[] = {
16708 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
16709 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
16710 { }
16711};
16712
Kailang Yangbdd148a2007-05-08 15:19:08 +020016713static struct hda_verb alc861vd_lenovo_unsol_verbs[] = {
16714 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16715 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16716 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
16717 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
Kailang Yangea1fb292008-08-26 12:58:38 +020016718 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
Kailang Yangbdd148a2007-05-08 15:19:08 +020016719 {}
16720};
16721
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016722static void alc861vd_lenovo_setup(struct hda_codec *codec)
Kailang Yangbdd148a2007-05-08 15:19:08 +020016723{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016724 struct alc_spec *spec = codec->spec;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016725 spec->autocfg.hp_pins[0] = 0x1b;
16726 spec->autocfg.speaker_pins[0] = 0x14;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016727}
16728
16729static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
16730{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016731 alc_automute_amp(codec);
Anisse Astiereeb43382010-12-16 12:19:47 +010016732 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016733}
16734
16735static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
16736 unsigned int res)
16737{
16738 switch (res >> 26) {
Kailang Yangbdd148a2007-05-08 15:19:08 +020016739 case ALC880_MIC_EVENT:
Anisse Astiereeb43382010-12-16 12:19:47 +010016740 alc88x_simple_mic_automute(codec);
Kailang Yangbdd148a2007-05-08 15:19:08 +020016741 break;
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016742 default:
16743 alc_automute_amp_unsol_event(codec, res);
16744 break;
Kailang Yangbdd148a2007-05-08 15:19:08 +020016745 }
16746}
16747
Kailang Yang272a5272007-05-14 11:00:38 +020016748static struct hda_verb alc861vd_dallas_verbs[] = {
16749 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16750 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16751 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16752 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
16753
16754 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16755 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
16756 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16757 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16758 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16759 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
16760 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
16761 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016762
Kailang Yang272a5272007-05-14 11:00:38 +020016763 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16764 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16765 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16766 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16767 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16768 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16769 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
16770 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
16771
16772 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16773 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16774 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
16775 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
16776 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16777 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16778 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16779 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
16780
16781 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
16782 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
16783 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
16784 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
16785
16786 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
Kailang Yangea1fb292008-08-26 12:58:38 +020016787 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yang272a5272007-05-14 11:00:38 +020016788 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
16789
16790 { } /* end */
16791};
16792
16793/* toggle speaker-output according to the hp-jack state */
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016794static void alc861vd_dallas_setup(struct hda_codec *codec)
Kailang Yang272a5272007-05-14 11:00:38 +020016795{
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016796 struct alc_spec *spec = codec->spec;
Kailang Yang272a5272007-05-14 11:00:38 +020016797
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016798 spec->autocfg.hp_pins[0] = 0x15;
16799 spec->autocfg.speaker_pins[0] = 0x14;
Kailang Yang272a5272007-05-14 11:00:38 +020016800}
16801
Takashi Iwaicb53c622007-08-10 17:21:45 +020016802#ifdef CONFIG_SND_HDA_POWER_SAVE
16803#define alc861vd_loopbacks alc880_loopbacks
16804#endif
16805
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016806/* pcm configuration: identical with ALC880 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016807#define alc861vd_pcm_analog_playback alc880_pcm_analog_playback
16808#define alc861vd_pcm_analog_capture alc880_pcm_analog_capture
16809#define alc861vd_pcm_digital_playback alc880_pcm_digital_playback
16810#define alc861vd_pcm_digital_capture alc880_pcm_digital_capture
16811
16812/*
16813 * configuration and preset
16814 */
16815static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
16816 [ALC660VD_3ST] = "3stack-660",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016817 [ALC660VD_3ST_DIG] = "3stack-660-digout",
Takashi Iwai13c94742008-11-05 08:06:08 +010016818 [ALC660VD_ASUS_V1S] = "asus-v1s",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016819 [ALC861VD_3ST] = "3stack",
16820 [ALC861VD_3ST_DIG] = "3stack-digout",
16821 [ALC861VD_6ST_DIG] = "6stack-digout",
Kailang Yangbdd148a2007-05-08 15:19:08 +020016822 [ALC861VD_LENOVO] = "lenovo",
Kailang Yang272a5272007-05-14 11:00:38 +020016823 [ALC861VD_DALLAS] = "dallas",
Takashi Iwai983f8ae2007-08-15 16:44:04 +020016824 [ALC861VD_HP] = "hp",
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016825 [ALC861VD_AUTO] = "auto",
16826};
16827
16828static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016829 SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
16830 SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
Takashi Iwai07e038b2007-02-15 18:23:41 +010016831 SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020016832 /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
Takashi Iwai13c94742008-11-05 08:06:08 +010016833 SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
Mike Crash6963f842007-06-25 12:12:51 +020016834 SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016835 SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
Takashi Iwaiac3e3742007-12-17 17:14:18 +010016836 SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai38baf5a2007-08-16 17:52:43 +020016837 /*SND_PCI_QUIRK(0x1179, 0xff00, "DALLAS", ALC861VD_DALLAS),*/ /*lenovo*/
Takashi Iwaice577e82009-08-03 08:23:52 +020016838 SND_PCI_QUIRK(0x1179, 0xff01, "Toshiba A135", ALC861VD_LENOVO),
Takashi Iwai542d7c62007-08-16 18:57:30 +020016839 SND_PCI_QUIRK(0x1179, 0xff03, "Toshiba P205", ALC861VD_LENOVO),
Tobin Davisb419f342008-03-07 11:57:51 +010016840 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_DALLAS),
Takashi Iwai39c5d412007-08-15 16:24:17 +020016841 SND_PCI_QUIRK(0x1565, 0x820d, "Biostar NF61S SE", ALC861VD_6ST_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010016842 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", ALC861VD_LENOVO),
Tobin Davis625dc0b2007-07-30 21:42:10 +020016843 SND_PCI_QUIRK(0x1849, 0x0862, "ASRock K8NF6G-VSTA", ALC861VD_6ST_DIG),
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016844 {}
16845};
16846
16847static struct alc_config_preset alc861vd_presets[] = {
16848 [ALC660VD_3ST] = {
16849 .mixers = { alc861vd_3st_mixer },
16850 .init_verbs = { alc861vd_volume_init_verbs,
16851 alc861vd_3stack_init_verbs },
16852 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16853 .dac_nids = alc660vd_dac_nids,
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016854 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16855 .channel_mode = alc861vd_3stack_2ch_modes,
16856 .input_mux = &alc861vd_capture_source,
16857 },
Mike Crash6963f842007-06-25 12:12:51 +020016858 [ALC660VD_3ST_DIG] = {
16859 .mixers = { alc861vd_3st_mixer },
16860 .init_verbs = { alc861vd_volume_init_verbs,
16861 alc861vd_3stack_init_verbs },
16862 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16863 .dac_nids = alc660vd_dac_nids,
16864 .dig_out_nid = ALC861VD_DIGOUT_NID,
Mike Crash6963f842007-06-25 12:12:51 +020016865 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16866 .channel_mode = alc861vd_3stack_2ch_modes,
16867 .input_mux = &alc861vd_capture_source,
16868 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016869 [ALC861VD_3ST] = {
16870 .mixers = { alc861vd_3st_mixer },
16871 .init_verbs = { alc861vd_volume_init_verbs,
16872 alc861vd_3stack_init_verbs },
16873 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16874 .dac_nids = alc861vd_dac_nids,
16875 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16876 .channel_mode = alc861vd_3stack_2ch_modes,
16877 .input_mux = &alc861vd_capture_source,
16878 },
16879 [ALC861VD_3ST_DIG] = {
16880 .mixers = { alc861vd_3st_mixer },
16881 .init_verbs = { alc861vd_volume_init_verbs,
16882 alc861vd_3stack_init_verbs },
16883 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16884 .dac_nids = alc861vd_dac_nids,
16885 .dig_out_nid = ALC861VD_DIGOUT_NID,
16886 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16887 .channel_mode = alc861vd_3stack_2ch_modes,
16888 .input_mux = &alc861vd_capture_source,
16889 },
16890 [ALC861VD_6ST_DIG] = {
16891 .mixers = { alc861vd_6st_mixer, alc861vd_chmode_mixer },
16892 .init_verbs = { alc861vd_volume_init_verbs,
16893 alc861vd_6stack_init_verbs },
16894 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16895 .dac_nids = alc861vd_dac_nids,
16896 .dig_out_nid = ALC861VD_DIGOUT_NID,
16897 .num_channel_mode = ARRAY_SIZE(alc861vd_6stack_modes),
16898 .channel_mode = alc861vd_6stack_modes,
16899 .input_mux = &alc861vd_capture_source,
16900 },
Kailang Yangbdd148a2007-05-08 15:19:08 +020016901 [ALC861VD_LENOVO] = {
16902 .mixers = { alc861vd_lenovo_mixer },
16903 .init_verbs = { alc861vd_volume_init_verbs,
16904 alc861vd_3stack_init_verbs,
16905 alc861vd_eapd_verbs,
16906 alc861vd_lenovo_unsol_verbs },
16907 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16908 .dac_nids = alc660vd_dac_nids,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016909 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16910 .channel_mode = alc861vd_3stack_2ch_modes,
16911 .input_mux = &alc861vd_capture_source,
16912 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016913 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016914 .init_hook = alc861vd_lenovo_init_hook,
Kailang Yangbdd148a2007-05-08 15:19:08 +020016915 },
Kailang Yang272a5272007-05-14 11:00:38 +020016916 [ALC861VD_DALLAS] = {
16917 .mixers = { alc861vd_dallas_mixer },
16918 .init_verbs = { alc861vd_dallas_verbs },
16919 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16920 .dac_nids = alc861vd_dac_nids,
Kailang Yang272a5272007-05-14 11:00:38 +020016921 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16922 .channel_mode = alc861vd_3stack_2ch_modes,
16923 .input_mux = &alc861vd_dallas_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016924 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016925 .setup = alc861vd_dallas_setup,
16926 .init_hook = alc_automute_amp,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016927 },
16928 [ALC861VD_HP] = {
16929 .mixers = { alc861vd_hp_mixer },
16930 .init_verbs = { alc861vd_dallas_verbs, alc861vd_eapd_verbs },
16931 .num_dacs = ARRAY_SIZE(alc861vd_dac_nids),
16932 .dac_nids = alc861vd_dac_nids,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016933 .dig_out_nid = ALC861VD_DIGOUT_NID,
Kailang Yangd1a991a2007-08-15 16:21:59 +020016934 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16935 .channel_mode = alc861vd_3stack_2ch_modes,
16936 .input_mux = &alc861vd_hp_capture_source,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016937 .unsol_event = alc_automute_amp_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016938 .setup = alc861vd_dallas_setup,
16939 .init_hook = alc_automute_amp,
Kailang Yangea1fb292008-08-26 12:58:38 +020016940 },
Takashi Iwai13c94742008-11-05 08:06:08 +010016941 [ALC660VD_ASUS_V1S] = {
16942 .mixers = { alc861vd_lenovo_mixer },
16943 .init_verbs = { alc861vd_volume_init_verbs,
16944 alc861vd_3stack_init_verbs,
16945 alc861vd_eapd_verbs,
16946 alc861vd_lenovo_unsol_verbs },
16947 .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
16948 .dac_nids = alc660vd_dac_nids,
16949 .dig_out_nid = ALC861VD_DIGOUT_NID,
16950 .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
16951 .channel_mode = alc861vd_3stack_2ch_modes,
16952 .input_mux = &alc861vd_capture_source,
16953 .unsol_event = alc861vd_lenovo_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020016954 .setup = alc861vd_lenovo_setup,
Takashi Iwaia9fd4f32009-05-08 15:57:59 +020016955 .init_hook = alc861vd_lenovo_init_hook,
Takashi Iwai13c94742008-11-05 08:06:08 +010016956 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016957};
16958
16959/*
16960 * BIOS auto configuration
16961 */
Takashi Iwai05f5f472009-08-25 13:10:18 +020016962static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
16963 const struct auto_pin_cfg *cfg)
16964{
Herton Ronaldo Krzesinski71675942010-11-25 00:08:01 -020016965 return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
Takashi Iwai05f5f472009-08-25 13:10:18 +020016966}
16967
16968
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016969static void alc861vd_auto_set_output_and_unmute(struct hda_codec *codec,
16970 hda_nid_t nid, int pin_type, int dac_idx)
16971{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016972 alc_set_pin_output(codec, nid, pin_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016973}
16974
16975static void alc861vd_auto_init_multi_out(struct hda_codec *codec)
16976{
16977 struct alc_spec *spec = codec->spec;
16978 int i;
16979
16980 for (i = 0; i <= HDA_SIDE; i++) {
16981 hda_nid_t nid = spec->autocfg.line_out_pins[i];
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016982 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016983 if (nid)
16984 alc861vd_auto_set_output_and_unmute(codec, nid,
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020016985 pin_type, i);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016986 }
16987}
16988
16989
16990static void alc861vd_auto_init_hp_out(struct hda_codec *codec)
16991{
16992 struct alc_spec *spec = codec->spec;
16993 hda_nid_t pin;
16994
16995 pin = spec->autocfg.hp_pins[0];
Sasha Alexandrdef319f2009-06-16 16:00:15 -040016996 if (pin) /* connect to front and use dac 0 */
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010016997 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010016998 pin = spec->autocfg.speaker_pins[0];
16999 if (pin)
17000 alc861vd_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017001}
17002
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017003#define ALC861VD_PIN_CD_NID ALC880_PIN_CD_NID
17004
17005static void alc861vd_auto_init_analog_input(struct hda_codec *codec)
17006{
17007 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017008 struct auto_pin_cfg *cfg = &spec->autocfg;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017009 int i;
17010
Takashi Iwai66ceeb62010-08-30 13:05:52 +020017011 for (i = 0; i < cfg->num_inputs; i++) {
17012 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017013 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020017014 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwaie82c0252009-03-23 15:17:38 +010017015 if (nid != ALC861VD_PIN_CD_NID &&
17016 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017017 snd_hda_codec_write(codec, nid, 0,
17018 AC_VERB_SET_AMP_GAIN_MUTE,
17019 AMP_OUT_MUTE);
17020 }
17021 }
17022}
17023
Takashi Iwaif511b012008-08-15 16:46:42 +020017024#define alc861vd_auto_init_input_src alc882_auto_init_input_src
17025
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017026#define alc861vd_idx_to_mixer_vol(nid) ((nid) + 0x02)
17027#define alc861vd_idx_to_mixer_switch(nid) ((nid) + 0x0c)
17028
17029/* add playback controls from the parsed DAC table */
17030/* Based on ALC880 version. But ALC861VD has separate,
17031 * different NIDs for mute/unmute switch and volume control */
17032static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec,
17033 const struct auto_pin_cfg *cfg)
17034{
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017035 static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"};
17036 hda_nid_t nid_v, nid_s;
17037 int i, err;
17038
17039 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017040 if (!spec->multiout.dac_nids[i])
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017041 continue;
17042 nid_v = alc861vd_idx_to_mixer_vol(
17043 alc880_dac_to_idx(
17044 spec->multiout.dac_nids[i]));
17045 nid_s = alc861vd_idx_to_mixer_switch(
17046 alc880_dac_to_idx(
17047 spec->multiout.dac_nids[i]));
17048
17049 if (i == 2) {
17050 /* Center/LFE */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017051 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17052 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017053 HDA_COMPOSE_AMP_VAL(nid_v, 1, 0,
17054 HDA_OUTPUT));
17055 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017056 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017057 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL,
17058 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017059 HDA_COMPOSE_AMP_VAL(nid_v, 2, 0,
17060 HDA_OUTPUT));
17061 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017062 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017063 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17064 "Center",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017065 HDA_COMPOSE_AMP_VAL(nid_s, 1, 2,
17066 HDA_INPUT));
17067 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017068 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017069 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE,
17070 "LFE",
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017071 HDA_COMPOSE_AMP_VAL(nid_s, 2, 2,
17072 HDA_INPUT));
17073 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017074 return err;
17075 } else {
Takashi Iwaia4fcd492009-08-25 16:12:15 +020017076 const char *pfx;
17077 if (cfg->line_outs == 1 &&
17078 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
17079 if (!cfg->hp_pins)
17080 pfx = "Speaker";
17081 else
17082 pfx = "PCM";
17083 } else
17084 pfx = chname[i];
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017085 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017086 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0,
17087 HDA_OUTPUT));
17088 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017089 return err;
Takashi Iwaia4fcd492009-08-25 16:12:15 +020017090 if (cfg->line_outs == 1 &&
17091 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
17092 pfx = "Speaker";
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017093 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Kailang Yangbdd148a2007-05-08 15:19:08 +020017094 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017095 HDA_INPUT));
17096 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017097 return err;
17098 }
17099 }
17100 return 0;
17101}
17102
17103/* add playback controls for speaker and HP outputs */
17104/* Based on ALC880 version. But ALC861VD has separate,
17105 * different NIDs for mute/unmute switch and volume control */
17106static int alc861vd_auto_create_extra_out(struct alc_spec *spec,
17107 hda_nid_t pin, const char *pfx)
17108{
17109 hda_nid_t nid_v, nid_s;
17110 int err;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017111
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017112 if (!pin)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017113 return 0;
17114
17115 if (alc880_is_fixed_pin(pin)) {
17116 nid_v = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
17117 /* specify the DAC as the extra output */
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017118 if (!spec->multiout.hp_nid)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017119 spec->multiout.hp_nid = nid_v;
17120 else
17121 spec->multiout.extra_out_nid[0] = nid_v;
17122 /* control HP volume/switch on the output mixer amp */
17123 nid_v = alc861vd_idx_to_mixer_vol(
17124 alc880_fixed_pin_idx(pin));
17125 nid_s = alc861vd_idx_to_mixer_switch(
17126 alc880_fixed_pin_idx(pin));
17127
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017128 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017129 HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT));
17130 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017131 return err;
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017132 err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017133 HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT));
17134 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017135 return err;
17136 } else if (alc880_is_multi_pin(pin)) {
17137 /* set manual connection */
17138 /* we have only a switch on HP-out PIN */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020017139 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017140 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
17141 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017142 return err;
17143 }
17144 return 0;
17145}
17146
17147/* parse the BIOS configuration and set up the alc_spec
17148 * return 1 if successful, 0 if the proper config is not found,
17149 * or a negative error code
17150 * Based on ALC880 version - had to change it to override
17151 * alc880_auto_create_extra_out and alc880_auto_create_multi_out_ctls */
17152static int alc861vd_parse_auto_config(struct hda_codec *codec)
17153{
17154 struct alc_spec *spec = codec->spec;
17155 int err;
17156 static hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
17157
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017158 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
17159 alc861vd_ignore);
17160 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017161 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017162 if (!spec->autocfg.line_outs)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017163 return 0; /* can't find valid BIOS pin config */
17164
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017165 err = alc880_auto_fill_dac_nids(spec, &spec->autocfg);
17166 if (err < 0)
17167 return err;
17168 err = alc861vd_auto_create_multi_out_ctls(spec, &spec->autocfg);
17169 if (err < 0)
17170 return err;
17171 err = alc861vd_auto_create_extra_out(spec,
17172 spec->autocfg.speaker_pins[0],
17173 "Speaker");
17174 if (err < 0)
17175 return err;
17176 err = alc861vd_auto_create_extra_out(spec,
17177 spec->autocfg.hp_pins[0],
17178 "Headphone");
17179 if (err < 0)
17180 return err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020017181 err = alc861vd_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017182 if (err < 0)
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017183 return err;
17184
17185 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
17186
Takashi Iwai757899a2010-07-30 10:48:14 +020017187 alc_auto_parse_digital(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017188
Takashi Iwai603c4012008-07-30 15:01:44 +020017189 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010017190 add_mixer(spec, spec->kctls.list);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017191
Takashi Iwaid88897e2008-10-31 15:01:37 +010017192 add_verb(spec, alc861vd_volume_init_verbs);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017193
17194 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020017195 spec->input_mux = &spec->private_imux[0];
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017196
Takashi Iwai776e1842007-08-29 15:07:11 +020017197 err = alc_auto_add_mic_boost(codec);
17198 if (err < 0)
17199 return err;
17200
Kailang Yang6227cdc2010-02-25 08:36:52 +010017201 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020017202
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017203 return 1;
17204}
17205
17206/* additional initialization for auto-configuration model */
17207static void alc861vd_auto_init(struct hda_codec *codec)
17208{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017209 struct alc_spec *spec = codec->spec;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017210 alc861vd_auto_init_multi_out(codec);
17211 alc861vd_auto_init_hp_out(codec);
17212 alc861vd_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020017213 alc861vd_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020017214 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010017215 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020017216 alc_inithook(codec);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017217}
17218
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017219enum {
17220 ALC660VD_FIX_ASUS_GPIO1
17221};
17222
17223/* reset GPIO1 */
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017224static const struct alc_fixup alc861vd_fixups[] = {
17225 [ALC660VD_FIX_ASUS_GPIO1] = {
Takashi Iwai73413b12010-08-30 09:39:57 +020017226 .verbs = (const struct hda_verb[]) {
17227 {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
17228 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
17229 {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
17230 { }
17231 }
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017232 },
17233};
17234
17235static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
17236 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
17237 {}
17238};
17239
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017240static int patch_alc861vd(struct hda_codec *codec)
17241{
17242 struct alc_spec *spec;
17243 int err, board_config;
17244
17245 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
17246 if (spec == NULL)
17247 return -ENOMEM;
17248
17249 codec->spec = spec;
17250
17251 board_config = snd_hda_check_board_config(codec, ALC861VD_MODEL_LAST,
17252 alc861vd_models,
17253 alc861vd_cfg_tbl);
17254
17255 if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020017256 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
17257 codec->chip_name);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017258 board_config = ALC861VD_AUTO;
17259 }
17260
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017261 if (board_config == ALC861VD_AUTO)
17262 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1);
Takashi Iwaif8f25ba2009-10-06 08:31:29 +020017263
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017264 if (board_config == ALC861VD_AUTO) {
17265 /* automatic parse from the BIOS config */
17266 err = alc861vd_parse_auto_config(codec);
17267 if (err < 0) {
17268 alc_free(codec);
17269 return err;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020017270 } else if (!err) {
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017271 printk(KERN_INFO
17272 "hda_codec: Cannot set up configuration "
17273 "from BIOS. Using base mode...\n");
17274 board_config = ALC861VD_3ST;
17275 }
17276 }
17277
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090017278 err = snd_hda_attach_beep_device(codec, 0x23);
17279 if (err < 0) {
17280 alc_free(codec);
17281 return err;
17282 }
17283
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017284 if (board_config != ALC861VD_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020017285 setup_preset(codec, &alc861vd_presets[board_config]);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017286
Kailang Yang2f893282008-05-27 12:14:47 +020017287 if (codec->vendor_id == 0x10ec0660) {
Kailang Yangf9423e72008-05-27 12:32:25 +020017288 /* always turn on EAPD */
Takashi Iwaid88897e2008-10-31 15:01:37 +010017289 add_verb(spec, alc660vd_eapd_verbs);
Kailang Yang2f893282008-05-27 12:14:47 +020017290 }
17291
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017292 spec->stream_analog_playback = &alc861vd_pcm_analog_playback;
17293 spec->stream_analog_capture = &alc861vd_pcm_analog_capture;
17294
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017295 spec->stream_digital_playback = &alc861vd_pcm_digital_playback;
17296 spec->stream_digital_capture = &alc861vd_pcm_digital_capture;
17297
Takashi Iwaidd704692009-08-11 08:45:11 +020017298 if (!spec->adc_nids) {
17299 spec->adc_nids = alc861vd_adc_nids;
17300 spec->num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids);
17301 }
17302 if (!spec->capsrc_nids)
17303 spec->capsrc_nids = alc861vd_capsrc_nids;
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017304
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017305 set_capture_mixer(codec);
Takashi Iwai45bdd1c2009-02-06 16:11:25 +010017306 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017307
Takashi Iwai2134ea42008-01-10 16:53:55 +010017308 spec->vmaster_nid = 0x02;
17309
Takashi Iwai7fa90e82010-04-12 08:49:00 +020017310 if (board_config == ALC861VD_AUTO)
17311 alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0);
17312
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017313 codec->patch_ops = alc_patch_ops;
17314
17315 if (board_config == ALC861VD_AUTO)
17316 spec->init_hook = alc861vd_auto_init;
Takashi Iwaicb53c622007-08-10 17:21:45 +020017317#ifdef CONFIG_SND_HDA_POWER_SAVE
17318 if (!spec->loopback.amplist)
17319 spec->loopback.amplist = alc861vd_loopbacks;
17320#endif
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010017321
17322 return 0;
17323}
17324
17325/*
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017326 * ALC662 support
17327 *
17328 * ALC662 is almost identical with ALC880 but has cleaner and more flexible
17329 * configuration. Each pin widget can choose any input DACs and a mixer.
17330 * Each ADC is connected from a mixer of all inputs. This makes possible
17331 * 6-channel independent captures.
17332 *
17333 * In addition, an independent DAC for the multi-playback (not used in this
17334 * driver yet).
17335 */
17336#define ALC662_DIGOUT_NID 0x06
17337#define ALC662_DIGIN_NID 0x0a
17338
17339static hda_nid_t alc662_dac_nids[4] = {
17340 /* front, rear, clfe, rear_surr */
17341 0x02, 0x03, 0x04
17342};
17343
Kailang Yang622e84c2009-04-21 07:39:04 +020017344static hda_nid_t alc272_dac_nids[2] = {
17345 0x02, 0x03
17346};
17347
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017348static hda_nid_t alc662_adc_nids[2] = {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017349 /* ADC1-2 */
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017350 0x09, 0x08
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017351};
Takashi Iwaie1406342008-02-11 18:32:32 +010017352
Kailang Yang622e84c2009-04-21 07:39:04 +020017353static hda_nid_t alc272_adc_nids[1] = {
17354 /* ADC1-2 */
17355 0x08,
17356};
17357
Takashi Iwaib59bdf32009-08-11 09:47:30 +020017358static hda_nid_t alc662_capsrc_nids[2] = { 0x22, 0x23 };
Kailang Yang622e84c2009-04-21 07:39:04 +020017359static hda_nid_t alc272_capsrc_nids[1] = { 0x23 };
17360
Takashi Iwaie1406342008-02-11 18:32:32 +010017361
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017362/* input MUX */
17363/* FIXME: should be a matrix-type input source selection */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017364static struct hda_input_mux alc662_capture_source = {
17365 .num_items = 4,
17366 .items = {
17367 { "Mic", 0x0 },
17368 { "Front Mic", 0x1 },
17369 { "Line", 0x2 },
17370 { "CD", 0x4 },
17371 },
17372};
17373
17374static struct hda_input_mux alc662_lenovo_101e_capture_source = {
17375 .num_items = 2,
17376 .items = {
17377 { "Mic", 0x1 },
17378 { "Line", 0x2 },
17379 },
17380};
Kailang Yang291702f2007-10-16 14:28:03 +020017381
Kailang Yang6dda9f42008-05-27 12:05:31 +020017382static struct hda_input_mux alc663_capture_source = {
17383 .num_items = 3,
17384 .items = {
17385 { "Mic", 0x0 },
17386 { "Front Mic", 0x1 },
17387 { "Line", 0x2 },
17388 },
17389};
17390
Takashi Iwai4f5d17062009-08-11 18:17:46 +020017391#if 0 /* set to 1 for testing other input sources below */
Chris Pockelé9541ba12009-05-12 08:08:53 +020017392static struct hda_input_mux alc272_nc10_capture_source = {
17393 .num_items = 16,
17394 .items = {
17395 { "Autoselect Mic", 0x0 },
17396 { "Internal Mic", 0x1 },
17397 { "In-0x02", 0x2 },
17398 { "In-0x03", 0x3 },
17399 { "In-0x04", 0x4 },
17400 { "In-0x05", 0x5 },
17401 { "In-0x06", 0x6 },
17402 { "In-0x07", 0x7 },
17403 { "In-0x08", 0x8 },
17404 { "In-0x09", 0x9 },
17405 { "In-0x0a", 0x0a },
17406 { "In-0x0b", 0x0b },
17407 { "In-0x0c", 0x0c },
17408 { "In-0x0d", 0x0d },
17409 { "In-0x0e", 0x0e },
17410 { "In-0x0f", 0x0f },
17411 },
17412};
17413#endif
17414
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017415/*
17416 * 2ch mode
17417 */
17418static struct hda_channel_mode alc662_3ST_2ch_modes[1] = {
17419 { 2, NULL }
17420};
17421
17422/*
17423 * 2ch mode
17424 */
17425static struct hda_verb alc662_3ST_ch2_init[] = {
17426 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
17427 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17428 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
17429 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
17430 { } /* end */
17431};
17432
17433/*
17434 * 6ch mode
17435 */
17436static struct hda_verb alc662_3ST_ch6_init[] = {
17437 { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17438 { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17439 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 },
17440 { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17441 { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
17442 { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 },
17443 { } /* end */
17444};
17445
17446static struct hda_channel_mode alc662_3ST_6ch_modes[2] = {
17447 { 2, alc662_3ST_ch2_init },
17448 { 6, alc662_3ST_ch6_init },
17449};
17450
17451/*
17452 * 2ch mode
17453 */
17454static struct hda_verb alc662_sixstack_ch6_init[] = {
17455 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17456 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 },
17457 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17458 { } /* end */
17459};
17460
17461/*
17462 * 6ch mode
17463 */
17464static struct hda_verb alc662_sixstack_ch8_init[] = {
17465 { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17466 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17467 { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
17468 { } /* end */
17469};
17470
17471static struct hda_channel_mode alc662_5stack_modes[2] = {
17472 { 2, alc662_sixstack_ch6_init },
17473 { 6, alc662_sixstack_ch8_init },
17474};
17475
17476/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17
17477 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b
17478 */
17479
17480static struct snd_kcontrol_new alc662_base_mixer[] = {
17481 /* output mixer control */
17482 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017483 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017484 HDA_CODEC_VOLUME("Surround Playback Volume", 0x3, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017485 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017486 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17487 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017488 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17489 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017490 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17491
17492 /*Input mixer control */
17493 HDA_CODEC_VOLUME("CD Playback Volume", 0xb, 0x4, HDA_INPUT),
17494 HDA_CODEC_MUTE("CD Playback Switch", 0xb, 0x4, HDA_INPUT),
17495 HDA_CODEC_VOLUME("Line Playback Volume", 0xb, 0x02, HDA_INPUT),
17496 HDA_CODEC_MUTE("Line Playback Switch", 0xb, 0x02, HDA_INPUT),
17497 HDA_CODEC_VOLUME("Mic Playback Volume", 0xb, 0x0, HDA_INPUT),
17498 HDA_CODEC_MUTE("Mic Playback Switch", 0xb, 0x0, HDA_INPUT),
17499 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0xb, 0x01, HDA_INPUT),
17500 HDA_CODEC_MUTE("Front Mic Playback Switch", 0xb, 0x01, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017501 { } /* end */
17502};
17503
17504static struct snd_kcontrol_new alc662_3ST_2ch_mixer[] = {
17505 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017506 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017507 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17508 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17509 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17510 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17511 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17512 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17513 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17514 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17515 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017516 { } /* end */
17517};
17518
17519static struct snd_kcontrol_new alc662_3ST_6ch_mixer[] = {
17520 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017521 HDA_CODEC_MUTE("Front Playback Switch", 0x0c, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017522 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017523 HDA_CODEC_MUTE("Surround Playback Switch", 0x0d, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017524 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17525 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Herton Ronaldo Krzesinski7055ad82008-03-14 12:52:20 +010017526 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x0, HDA_INPUT),
17527 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x0, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017528 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17529 HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
17530 HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
17531 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17532 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17533 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17534 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17535 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17536 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017537 { } /* end */
17538};
17539
17540static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = {
17541 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17542 HDA_BIND_MUTE("Front Playback Switch", 0x02, 2, HDA_INPUT),
Takashi Iwai86cd9292008-01-28 18:09:56 +010017543 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17544 HDA_BIND_MUTE("Speaker Playback Switch", 0x03, 2, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017545 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17546 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17547 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17548 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17549 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017550 { } /* end */
17551};
17552
Kailang Yang291702f2007-10-16 14:28:03 +020017553static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017554 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17555 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yang291702f2007-10-16 14:28:03 +020017556
David Henningsson5f99f862011-01-04 15:24:24 +010017557 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017558 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17559 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017560
David Henningsson5f99f862011-01-04 15:24:24 +010017561 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017562 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17563 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang291702f2007-10-16 14:28:03 +020017564 { } /* end */
17565};
17566
Kailang Yang8c427222008-01-10 13:03:59 +010017567static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = {
Takashi Iwai42171c12009-05-08 14:11:43 +020017568 ALC262_HIPPO_MASTER_SWITCH,
17569 HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017570 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017571 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT),
17572 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT),
Kailang Yang8c427222008-01-10 13:03:59 +010017573 HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT),
17574 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17575 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17576 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17577 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17578 { } /* end */
17579};
17580
Kailang Yangf1d4e282008-08-26 14:03:29 +020017581static struct hda_bind_ctls alc663_asus_bind_master_vol = {
17582 .ops = &snd_hda_bind_vol,
17583 .values = {
17584 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17585 HDA_COMPOSE_AMP_VAL(0x03, 3, 0, HDA_OUTPUT),
17586 0
17587 },
17588};
17589
17590static struct hda_bind_ctls alc663_asus_one_bind_switch = {
17591 .ops = &snd_hda_bind_sw,
17592 .values = {
17593 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17594 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17595 0
17596 },
17597};
17598
Kailang Yang6dda9f42008-05-27 12:05:31 +020017599static struct snd_kcontrol_new alc663_m51va_mixer[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017600 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17601 HDA_BIND_SW("Master Playback Switch", &alc663_asus_one_bind_switch),
17602 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17603 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17604 { } /* end */
17605};
17606
17607static struct hda_bind_ctls alc663_asus_tree_bind_switch = {
17608 .ops = &snd_hda_bind_sw,
17609 .values = {
17610 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17611 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17612 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17613 0
17614 },
17615};
17616
17617static struct snd_kcontrol_new alc663_two_hp_m1_mixer[] = {
17618 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17619 HDA_BIND_SW("Master Playback Switch", &alc663_asus_tree_bind_switch),
17620 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17621 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17622 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17623 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17624
17625 { } /* end */
17626};
17627
17628static struct hda_bind_ctls alc663_asus_four_bind_switch = {
17629 .ops = &snd_hda_bind_sw,
17630 .values = {
17631 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17632 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17633 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17634 0
17635 },
17636};
17637
17638static struct snd_kcontrol_new alc663_two_hp_m2_mixer[] = {
17639 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17640 HDA_BIND_SW("Master Playback Switch", &alc663_asus_four_bind_switch),
17641 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17642 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17643 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17644 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17645 { } /* end */
17646};
17647
17648static struct snd_kcontrol_new alc662_1bjd_mixer[] = {
Kailang Yang6dda9f42008-05-27 12:05:31 +020017649 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17650 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017651 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17652 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17653 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17654 HDA_CODEC_VOLUME("F-Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17655 HDA_CODEC_MUTE("F-Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17656 { } /* end */
17657};
17658
17659static struct hda_bind_ctls alc663_asus_two_bind_master_vol = {
17660 .ops = &snd_hda_bind_vol,
17661 .values = {
17662 HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
17663 HDA_COMPOSE_AMP_VAL(0x04, 3, 0, HDA_OUTPUT),
17664 0
17665 },
17666};
17667
17668static struct hda_bind_ctls alc663_asus_two_bind_switch = {
17669 .ops = &snd_hda_bind_sw,
17670 .values = {
17671 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17672 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT),
17673 0
17674 },
17675};
17676
17677static struct snd_kcontrol_new alc663_asus_21jd_clfe_mixer[] = {
17678 HDA_BIND_VOL("Master Playback Volume",
17679 &alc663_asus_two_bind_master_vol),
17680 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17681 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017682 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17683 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17684 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020017685 { } /* end */
17686};
17687
17688static struct snd_kcontrol_new alc663_asus_15jd_clfe_mixer[] = {
17689 HDA_BIND_VOL("Master Playback Volume", &alc663_asus_bind_master_vol),
17690 HDA_BIND_SW("Master Playback Switch", &alc663_asus_two_bind_switch),
17691 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17692 HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17693 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17694 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017695 { } /* end */
17696};
17697
17698static struct snd_kcontrol_new alc663_g71v_mixer[] = {
17699 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17700 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17701 HDA_CODEC_VOLUME("Front Playback Volume", 0x03, 0x0, HDA_OUTPUT),
17702 HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17703 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17704
17705 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17706 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017707 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17708 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017709 { } /* end */
17710};
17711
17712static struct snd_kcontrol_new alc663_g50v_mixer[] = {
17713 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
17714 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
17715 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17716
17717 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17718 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010017719 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17720 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yang6dda9f42008-05-27 12:05:31 +020017721 HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
17722 HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
17723 { } /* end */
17724};
17725
Kailang Yangebb83ee2009-12-17 12:23:00 +010017726static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = {
17727 .ops = &snd_hda_bind_sw,
17728 .values = {
17729 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17730 HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT),
17731 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17732 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
17733 HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
17734 0
17735 },
17736};
17737
17738static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = {
17739 .ops = &snd_hda_bind_sw,
17740 .values = {
17741 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
17742 HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT),
17743 0
17744 },
17745};
17746
17747static struct snd_kcontrol_new alc663_mode7_mixer[] = {
17748 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17749 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17750 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17751 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
17752 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17753 HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17754 HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17755 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
17756 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
17757 { } /* end */
17758};
17759
17760static struct snd_kcontrol_new alc663_mode8_mixer[] = {
17761 HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch),
17762 HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol),
17763 HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch),
17764 HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT),
17765 HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT),
17766 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
17767 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
17768 { } /* end */
17769};
17770
17771
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017772static struct snd_kcontrol_new alc662_chmode_mixer[] = {
17773 {
17774 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
17775 .name = "Channel Mode",
17776 .info = alc_ch_mode_info,
17777 .get = alc_ch_mode_get,
17778 .put = alc_ch_mode_put,
17779 },
17780 { } /* end */
17781};
17782
17783static struct hda_verb alc662_init_verbs[] = {
17784 /* ADC: mute amp left and right */
17785 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17786 {0x09, AC_VERB_SET_CONNECT_SEL, 0x00},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017787
Kailang Yangb60dd392007-09-20 12:50:29 +020017788 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17789 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17790 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17791 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17792 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17793 {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017794
17795 /* Front Pin: output 0 (0x0c) */
17796 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17797 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17798
17799 /* Rear Pin: output 1 (0x0d) */
17800 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17801 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17802
17803 /* CLFE Pin: output 2 (0x0e) */
17804 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17805 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17806
17807 /* Mic (rear) pin: input vref at 80% */
17808 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17809 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17810 /* Front Mic pin: input vref at 80% */
17811 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
17812 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17813 /* Line In pin: input */
17814 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17815 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17816 /* Line-2 In: Headphone output (output 0 - 0x0c) */
17817 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17818 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17819 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
17820 /* CD pin widget for input */
17821 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17822
17823 /* FIXME: use matrix-type input source selection */
17824 /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */
17825 /* Input mixer */
17826 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang291702f2007-10-16 14:28:03 +020017827 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017828
17829 /* always trun on EAPD */
17830 {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
17831 {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
17832
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017833 { }
17834};
17835
Kailang Yangcec27c82010-02-04 14:18:18 +010017836static struct hda_verb alc663_init_verbs[] = {
17837 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17838 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17839 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17840 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17841 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17842 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17843 { }
17844};
17845
17846static struct hda_verb alc272_init_verbs[] = {
17847 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17848 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
17849 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17850 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17851 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17852 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17853 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
17854 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17855 { }
17856};
17857
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017858static struct hda_verb alc662_sue_init_verbs[] = {
17859 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17860 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
Kailang Yang291702f2007-10-16 14:28:03 +020017861 {}
17862};
17863
17864static struct hda_verb alc662_eeepc_sue_init_verbs[] = {
17865 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17866 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17867 {}
Kailang Yangbc9f98a2007-04-12 13:06:07 +020017868};
17869
Kailang Yang8c427222008-01-10 13:03:59 +010017870/* Set Unsolicited Event*/
17871static struct hda_verb alc662_eeepc_ep20_sue_init_verbs[] = {
17872 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
17873 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17874 {}
17875};
17876
Kailang Yang6dda9f42008-05-27 12:05:31 +020017877static struct hda_verb alc663_m51va_init_verbs[] = {
Kailang Yangf1d4e282008-08-26 14:03:29 +020017878 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17879 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017880 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17881 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangf1d4e282008-08-26 14:03:29 +020017882 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17883 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17884 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
Kailang Yang6dda9f42008-05-27 12:05:31 +020017885 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17886 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17887 {}
17888};
17889
Kailang Yangf1d4e282008-08-26 14:03:29 +020017890static struct hda_verb alc663_21jd_amic_init_verbs[] = {
17891 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17892 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17893 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17894 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17895 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17896 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17897 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17898 {}
17899};
17900
17901static struct hda_verb alc662_1bjd_amic_init_verbs[] = {
17902 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17903 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17904 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17905 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17906 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17907 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17908 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17909 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17910 {}
17911};
17912
17913static struct hda_verb alc663_15jd_amic_init_verbs[] = {
17914 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17915 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17916 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17917 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17918 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17919 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17920 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17921 {}
17922};
17923
17924static struct hda_verb alc663_two_hp_amic_m1_init_verbs[] = {
17925 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17926 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17927 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17928 {0x21, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17929 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17930 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17931 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, /* Headphone */
17932 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17933 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17934 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17935 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17936 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17937 {}
17938};
17939
17940static struct hda_verb alc663_two_hp_amic_m2_init_verbs[] = {
17941 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17942 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17943 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17944 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17945 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17946 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17947 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17948 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17949 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
17950 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17951 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17952 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17953 {}
17954};
17955
Kailang Yang6dda9f42008-05-27 12:05:31 +020017956static struct hda_verb alc663_g71v_init_verbs[] = {
17957 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17958 /* {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, */
17959 /* {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, */ /* Headphone */
17960
17961 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17962 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17963 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17964
17965 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_FRONT_EVENT},
17966 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_MIC_EVENT},
17967 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|ALC880_HP_EVENT},
17968 {}
17969};
17970
17971static struct hda_verb alc663_g50v_init_verbs[] = {
17972 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17973 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17974 {0x21, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Headphone */
17975
17976 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17977 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17978 {}
17979};
17980
Kailang Yangf1d4e282008-08-26 14:03:29 +020017981static struct hda_verb alc662_ecs_init_verbs[] = {
17982 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0x701f},
17983 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17984 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
17985 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
17986 {}
17987};
17988
Kailang Yang622e84c2009-04-21 07:39:04 +020017989static struct hda_verb alc272_dell_zm1_init_verbs[] = {
17990 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17991 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17992 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17993 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
17994 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
17995 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
17996 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
17997 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
17998 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
17999 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18000 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18001 {}
18002};
18003
18004static struct hda_verb alc272_dell_init_verbs[] = {
18005 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18006 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18007 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18008 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18009 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18010 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18011 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18012 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18013 {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18014 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18015 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18016 {}
18017};
18018
Kailang Yangebb83ee2009-12-17 12:23:00 +010018019static struct hda_verb alc663_mode7_init_verbs[] = {
18020 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18021 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18022 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18023 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18024 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18025 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18026 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01},
18027 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18028 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18029 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18030 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18031 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18032 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18033 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18034 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18035 {}
18036};
18037
18038static struct hda_verb alc663_mode8_init_verbs[] = {
18039 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18040 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18041 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18042 {0x15, AC_VERB_SET_CONNECT_SEL, 0x01},
18043 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18044 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
18045 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18046 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
18047 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
18048 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
18049 {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */
18050 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
18051 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)},
18052 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18053 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT},
18054 {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
18055 {}
18056};
18057
Kailang Yangf1d4e282008-08-26 14:03:29 +020018058static struct snd_kcontrol_new alc662_auto_capture_mixer[] = {
18059 HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT),
18060 HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT),
18061 { } /* end */
18062};
18063
Kailang Yang622e84c2009-04-21 07:39:04 +020018064static struct snd_kcontrol_new alc272_auto_capture_mixer[] = {
18065 HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
18066 HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
18067 { } /* end */
18068};
18069
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018070static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec)
18071{
18072 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018073 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018074
Wu Fengguang864f92b2009-11-18 12:38:02 +080018075 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai47fd8302007-08-10 17:11:07 +020018076 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080018077
Takashi Iwai47fd8302007-08-10 17:11:07 +020018078 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18079 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018080}
18081
18082static void alc662_lenovo_101e_all_automute(struct hda_codec *codec)
18083{
18084 unsigned int present;
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018085 unsigned char bits;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018086
Wu Fengguang864f92b2009-11-18 12:38:02 +080018087 present = snd_hda_jack_detect(codec, 0x1b);
Takashi Iwai47fd8302007-08-10 17:11:07 +020018088 bits = present ? HDA_AMP_MUTE : 0;
Wu Fengguang864f92b2009-11-18 12:38:02 +080018089
Takashi Iwai47fd8302007-08-10 17:11:07 +020018090 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18091 HDA_AMP_MUTE, bits);
18092 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18093 HDA_AMP_MUTE, bits);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018094}
18095
18096static void alc662_lenovo_101e_unsol_event(struct hda_codec *codec,
18097 unsigned int res)
18098{
18099 if ((res >> 26) == ALC880_HP_EVENT)
18100 alc662_lenovo_101e_all_automute(codec);
18101 if ((res >> 26) == ALC880_FRONT_EVENT)
18102 alc662_lenovo_101e_ispeaker_automute(codec);
18103}
18104
Kailang Yang291702f2007-10-16 14:28:03 +020018105/* unsolicited event for HP jack sensing */
18106static void alc662_eeepc_unsol_event(struct hda_codec *codec,
18107 unsigned int res)
18108{
Kailang Yang291702f2007-10-16 14:28:03 +020018109 if ((res >> 26) == ALC880_MIC_EVENT)
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018110 alc_mic_automute(codec);
Takashi Iwai42171c12009-05-08 14:11:43 +020018111 else
18112 alc262_hippo_unsol_event(codec, res);
Kailang Yang291702f2007-10-16 14:28:03 +020018113}
18114
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018115static void alc662_eeepc_setup(struct hda_codec *codec)
Kailang Yang291702f2007-10-16 14:28:03 +020018116{
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018117 struct alc_spec *spec = codec->spec;
18118
18119 alc262_hippo1_setup(codec);
18120 spec->ext_mic.pin = 0x18;
18121 spec->ext_mic.mux_idx = 0;
18122 spec->int_mic.pin = 0x19;
18123 spec->int_mic.mux_idx = 1;
18124 spec->auto_mic = 1;
Kailang Yang291702f2007-10-16 14:28:03 +020018125}
18126
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018127static void alc662_eeepc_inithook(struct hda_codec *codec)
18128{
18129 alc262_hippo_automute(codec);
18130 alc_mic_automute(codec);
18131}
18132
18133static void alc662_eeepc_ep20_setup(struct hda_codec *codec)
Kailang Yang8c427222008-01-10 13:03:59 +010018134{
Takashi Iwai42171c12009-05-08 14:11:43 +020018135 struct alc_spec *spec = codec->spec;
18136
18137 spec->autocfg.hp_pins[0] = 0x14;
18138 spec->autocfg.speaker_pins[0] = 0x1b;
Kailang Yang8c427222008-01-10 13:03:59 +010018139}
18140
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018141#define alc662_eeepc_ep20_inithook alc262_hippo_master_update
18142
Kailang Yang6dda9f42008-05-27 12:05:31 +020018143static void alc663_m51va_speaker_automute(struct hda_codec *codec)
18144{
18145 unsigned int present;
18146 unsigned char bits;
18147
Wu Fengguang864f92b2009-11-18 12:38:02 +080018148 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018149 bits = present ? HDA_AMP_MUTE : 0;
Kailang Yangf1d4e282008-08-26 14:03:29 +020018150 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018151 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018152 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018153 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018154}
18155
18156static void alc663_21jd_two_speaker_automute(struct hda_codec *codec)
18157{
18158 unsigned int present;
18159 unsigned char bits;
18160
Wu Fengguang864f92b2009-11-18 12:38:02 +080018161 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018162 bits = present ? HDA_AMP_MUTE : 0;
18163 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018164 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018165 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018166 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018167 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018168 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018169 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018170 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018171}
18172
18173static void alc663_15jd_two_speaker_automute(struct hda_codec *codec)
18174{
18175 unsigned int present;
18176 unsigned char bits;
18177
Wu Fengguang864f92b2009-11-18 12:38:02 +080018178 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018179 bits = present ? HDA_AMP_MUTE : 0;
18180 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018181 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018182 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018183 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018184 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018185 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018186 snd_hda_codec_amp_stereo(codec, 0x0e, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018187 HDA_AMP_MUTE, bits);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018188}
18189
18190static void alc662_f5z_speaker_automute(struct hda_codec *codec)
18191{
18192 unsigned int present;
18193 unsigned char bits;
18194
Wu Fengguang864f92b2009-11-18 12:38:02 +080018195 present = snd_hda_jack_detect(codec, 0x1b);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018196 bits = present ? 0 : PIN_OUT;
18197 snd_hda_codec_write(codec, 0x14, 0,
18198 AC_VERB_SET_PIN_WIDGET_CONTROL, bits);
18199}
18200
18201static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec)
18202{
18203 unsigned int present1, present2;
18204
Wu Fengguang864f92b2009-11-18 12:38:02 +080018205 present1 = snd_hda_jack_detect(codec, 0x21);
18206 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018207
18208 if (present1 || present2) {
18209 snd_hda_codec_write_cache(codec, 0x14, 0,
18210 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18211 } else {
18212 snd_hda_codec_write_cache(codec, 0x14, 0,
18213 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18214 }
18215}
18216
18217static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec)
18218{
18219 unsigned int present1, present2;
18220
Wu Fengguang864f92b2009-11-18 12:38:02 +080018221 present1 = snd_hda_jack_detect(codec, 0x1b);
18222 present2 = snd_hda_jack_detect(codec, 0x15);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018223
18224 if (present1 || present2) {
18225 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018226 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018227 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018228 HDA_AMP_MUTE, HDA_AMP_MUTE);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018229 } else {
18230 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018231 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018232 snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 1,
Takashi Iwai5dbd5ec2010-03-29 09:16:24 +020018233 HDA_AMP_MUTE, 0);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018234 }
Kailang Yang6dda9f42008-05-27 12:05:31 +020018235}
18236
Kailang Yangebb83ee2009-12-17 12:23:00 +010018237static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec)
18238{
18239 unsigned int present1, present2;
18240
18241 present1 = snd_hda_codec_read(codec, 0x1b, 0,
18242 AC_VERB_GET_PIN_SENSE, 0)
18243 & AC_PINSENSE_PRESENCE;
18244 present2 = snd_hda_codec_read(codec, 0x21, 0,
18245 AC_VERB_GET_PIN_SENSE, 0)
18246 & AC_PINSENSE_PRESENCE;
18247
18248 if (present1 || present2) {
18249 snd_hda_codec_write_cache(codec, 0x14, 0,
18250 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18251 snd_hda_codec_write_cache(codec, 0x17, 0,
18252 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18253 } else {
18254 snd_hda_codec_write_cache(codec, 0x14, 0,
18255 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18256 snd_hda_codec_write_cache(codec, 0x17, 0,
18257 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18258 }
18259}
18260
18261static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec)
18262{
18263 unsigned int present1, present2;
18264
18265 present1 = snd_hda_codec_read(codec, 0x21, 0,
18266 AC_VERB_GET_PIN_SENSE, 0)
18267 & AC_PINSENSE_PRESENCE;
18268 present2 = snd_hda_codec_read(codec, 0x15, 0,
18269 AC_VERB_GET_PIN_SENSE, 0)
18270 & AC_PINSENSE_PRESENCE;
18271
18272 if (present1 || present2) {
18273 snd_hda_codec_write_cache(codec, 0x14, 0,
18274 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18275 snd_hda_codec_write_cache(codec, 0x17, 0,
18276 AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
18277 } else {
18278 snd_hda_codec_write_cache(codec, 0x14, 0,
18279 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18280 snd_hda_codec_write_cache(codec, 0x17, 0,
18281 AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
18282 }
18283}
18284
Kailang Yang6dda9f42008-05-27 12:05:31 +020018285static void alc663_m51va_unsol_event(struct hda_codec *codec,
18286 unsigned int res)
18287{
18288 switch (res >> 26) {
18289 case ALC880_HP_EVENT:
18290 alc663_m51va_speaker_automute(codec);
18291 break;
18292 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018293 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018294 break;
18295 }
18296}
18297
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018298static void alc663_m51va_setup(struct hda_codec *codec)
18299{
18300 struct alc_spec *spec = codec->spec;
18301 spec->ext_mic.pin = 0x18;
18302 spec->ext_mic.mux_idx = 0;
18303 spec->int_mic.pin = 0x12;
Kailang Yangebb83ee2009-12-17 12:23:00 +010018304 spec->int_mic.mux_idx = 9;
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018305 spec->auto_mic = 1;
18306}
18307
Kailang Yang6dda9f42008-05-27 12:05:31 +020018308static void alc663_m51va_inithook(struct hda_codec *codec)
18309{
18310 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018311 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018312}
18313
Kailang Yangf1d4e282008-08-26 14:03:29 +020018314/* ***************** Mode1 ******************************/
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018315#define alc663_mode1_unsol_event alc663_m51va_unsol_event
Kailang Yangebb83ee2009-12-17 12:23:00 +010018316
18317static void alc663_mode1_setup(struct hda_codec *codec)
18318{
18319 struct alc_spec *spec = codec->spec;
18320 spec->ext_mic.pin = 0x18;
18321 spec->ext_mic.mux_idx = 0;
18322 spec->int_mic.pin = 0x19;
18323 spec->int_mic.mux_idx = 1;
18324 spec->auto_mic = 1;
18325}
18326
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018327#define alc663_mode1_inithook alc663_m51va_inithook
Kailang Yangf1d4e282008-08-26 14:03:29 +020018328
Kailang Yangf1d4e282008-08-26 14:03:29 +020018329/* ***************** Mode2 ******************************/
18330static void alc662_mode2_unsol_event(struct hda_codec *codec,
18331 unsigned int res)
18332{
18333 switch (res >> 26) {
18334 case ALC880_HP_EVENT:
18335 alc662_f5z_speaker_automute(codec);
18336 break;
18337 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018338 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018339 break;
18340 }
18341}
18342
Kailang Yangebb83ee2009-12-17 12:23:00 +010018343#define alc662_mode2_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018344
Kailang Yangf1d4e282008-08-26 14:03:29 +020018345static void alc662_mode2_inithook(struct hda_codec *codec)
18346{
18347 alc662_f5z_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018348 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018349}
18350/* ***************** Mode3 ******************************/
18351static void alc663_mode3_unsol_event(struct hda_codec *codec,
18352 unsigned int res)
18353{
18354 switch (res >> 26) {
18355 case ALC880_HP_EVENT:
18356 alc663_two_hp_m1_speaker_automute(codec);
18357 break;
18358 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018359 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018360 break;
18361 }
18362}
18363
Kailang Yangebb83ee2009-12-17 12:23:00 +010018364#define alc663_mode3_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018365
Kailang Yangf1d4e282008-08-26 14:03:29 +020018366static void alc663_mode3_inithook(struct hda_codec *codec)
18367{
18368 alc663_two_hp_m1_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018369 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018370}
18371/* ***************** Mode4 ******************************/
18372static void alc663_mode4_unsol_event(struct hda_codec *codec,
18373 unsigned int res)
18374{
18375 switch (res >> 26) {
18376 case ALC880_HP_EVENT:
18377 alc663_21jd_two_speaker_automute(codec);
18378 break;
18379 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018380 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018381 break;
18382 }
18383}
18384
Kailang Yangebb83ee2009-12-17 12:23:00 +010018385#define alc663_mode4_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018386
Kailang Yangf1d4e282008-08-26 14:03:29 +020018387static void alc663_mode4_inithook(struct hda_codec *codec)
18388{
18389 alc663_21jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018390 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018391}
18392/* ***************** Mode5 ******************************/
18393static void alc663_mode5_unsol_event(struct hda_codec *codec,
18394 unsigned int res)
18395{
18396 switch (res >> 26) {
18397 case ALC880_HP_EVENT:
18398 alc663_15jd_two_speaker_automute(codec);
18399 break;
18400 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018401 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018402 break;
18403 }
18404}
18405
Kailang Yangebb83ee2009-12-17 12:23:00 +010018406#define alc663_mode5_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018407
Kailang Yangf1d4e282008-08-26 14:03:29 +020018408static void alc663_mode5_inithook(struct hda_codec *codec)
18409{
18410 alc663_15jd_two_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018411 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018412}
18413/* ***************** Mode6 ******************************/
18414static void alc663_mode6_unsol_event(struct hda_codec *codec,
18415 unsigned int res)
18416{
18417 switch (res >> 26) {
18418 case ALC880_HP_EVENT:
18419 alc663_two_hp_m2_speaker_automute(codec);
18420 break;
18421 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018422 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018423 break;
18424 }
18425}
18426
Kailang Yangebb83ee2009-12-17 12:23:00 +010018427#define alc663_mode6_setup alc663_mode1_setup
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018428
Kailang Yangf1d4e282008-08-26 14:03:29 +020018429static void alc663_mode6_inithook(struct hda_codec *codec)
18430{
18431 alc663_two_hp_m2_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018432 alc_mic_automute(codec);
Kailang Yangf1d4e282008-08-26 14:03:29 +020018433}
18434
Kailang Yangebb83ee2009-12-17 12:23:00 +010018435/* ***************** Mode7 ******************************/
18436static void alc663_mode7_unsol_event(struct hda_codec *codec,
18437 unsigned int res)
18438{
18439 switch (res >> 26) {
18440 case ALC880_HP_EVENT:
18441 alc663_two_hp_m7_speaker_automute(codec);
18442 break;
18443 case ALC880_MIC_EVENT:
18444 alc_mic_automute(codec);
18445 break;
18446 }
18447}
18448
18449#define alc663_mode7_setup alc663_mode1_setup
18450
18451static void alc663_mode7_inithook(struct hda_codec *codec)
18452{
18453 alc663_two_hp_m7_speaker_automute(codec);
18454 alc_mic_automute(codec);
18455}
18456
18457/* ***************** Mode8 ******************************/
18458static void alc663_mode8_unsol_event(struct hda_codec *codec,
18459 unsigned int res)
18460{
18461 switch (res >> 26) {
18462 case ALC880_HP_EVENT:
18463 alc663_two_hp_m8_speaker_automute(codec);
18464 break;
18465 case ALC880_MIC_EVENT:
18466 alc_mic_automute(codec);
18467 break;
18468 }
18469}
18470
18471#define alc663_mode8_setup alc663_m51va_setup
18472
18473static void alc663_mode8_inithook(struct hda_codec *codec)
18474{
18475 alc663_two_hp_m8_speaker_automute(codec);
18476 alc_mic_automute(codec);
18477}
18478
Kailang Yang6dda9f42008-05-27 12:05:31 +020018479static void alc663_g71v_hp_automute(struct hda_codec *codec)
18480{
18481 unsigned int present;
18482 unsigned char bits;
18483
Wu Fengguang864f92b2009-11-18 12:38:02 +080018484 present = snd_hda_jack_detect(codec, 0x21);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018485 bits = present ? HDA_AMP_MUTE : 0;
18486 snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0,
18487 HDA_AMP_MUTE, bits);
18488 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18489 HDA_AMP_MUTE, bits);
18490}
18491
18492static void alc663_g71v_front_automute(struct hda_codec *codec)
18493{
18494 unsigned int present;
18495 unsigned char bits;
18496
Wu Fengguang864f92b2009-11-18 12:38:02 +080018497 present = snd_hda_jack_detect(codec, 0x15);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018498 bits = present ? HDA_AMP_MUTE : 0;
18499 snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0,
18500 HDA_AMP_MUTE, bits);
18501}
18502
18503static void alc663_g71v_unsol_event(struct hda_codec *codec,
18504 unsigned int res)
18505{
18506 switch (res >> 26) {
18507 case ALC880_HP_EVENT:
18508 alc663_g71v_hp_automute(codec);
18509 break;
18510 case ALC880_FRONT_EVENT:
18511 alc663_g71v_front_automute(codec);
18512 break;
18513 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018514 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018515 break;
18516 }
18517}
18518
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018519#define alc663_g71v_setup alc663_m51va_setup
18520
Kailang Yang6dda9f42008-05-27 12:05:31 +020018521static void alc663_g71v_inithook(struct hda_codec *codec)
18522{
18523 alc663_g71v_front_automute(codec);
18524 alc663_g71v_hp_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018525 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018526}
18527
18528static void alc663_g50v_unsol_event(struct hda_codec *codec,
18529 unsigned int res)
18530{
18531 switch (res >> 26) {
18532 case ALC880_HP_EVENT:
18533 alc663_m51va_speaker_automute(codec);
18534 break;
18535 case ALC880_MIC_EVENT:
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018536 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018537 break;
18538 }
18539}
18540
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018541#define alc663_g50v_setup alc663_m51va_setup
18542
Kailang Yang6dda9f42008-05-27 12:05:31 +020018543static void alc663_g50v_inithook(struct hda_codec *codec)
18544{
18545 alc663_m51va_speaker_automute(codec);
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018546 alc_mic_automute(codec);
Kailang Yang6dda9f42008-05-27 12:05:31 +020018547}
18548
Kailang Yangf1d4e282008-08-26 14:03:29 +020018549static struct snd_kcontrol_new alc662_ecs_mixer[] = {
18550 HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT),
Takashi Iwai42171c12009-05-08 14:11:43 +020018551 ALC262_HIPPO_MASTER_SWITCH,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018552
David Henningsson5f99f862011-01-04 15:24:24 +010018553 HDA_CODEC_VOLUME("Mic/LineIn Boost Volume", 0x18, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018554 HDA_CODEC_VOLUME("Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT),
18555 HDA_CODEC_MUTE("Mic/LineIn Playback Switch", 0x0b, 0x0, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018556
David Henningsson5f99f862011-01-04 15:24:24 +010018557 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
David Henningsson10528022010-12-20 14:50:59 +010018558 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18559 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
Kailang Yangf1d4e282008-08-26 14:03:29 +020018560 { } /* end */
18561};
18562
Chris Pockelé9541ba12009-05-12 08:08:53 +020018563static struct snd_kcontrol_new alc272_nc10_mixer[] = {
18564 /* Master Playback automatically created from Speaker and Headphone */
18565 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT),
18566 HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT),
18567 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
18568 HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT),
18569
David Henningsson8607f7c2010-12-20 14:43:54 +010018570 HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
18571 HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018572 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018573
David Henningsson28c4edb2010-12-20 14:24:29 +010018574 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
18575 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010018576 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x19, 0, HDA_INPUT),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018577 { } /* end */
18578};
18579
Takashi Iwaicb53c622007-08-10 17:21:45 +020018580#ifdef CONFIG_SND_HDA_POWER_SAVE
18581#define alc662_loopbacks alc880_loopbacks
18582#endif
18583
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018584
Sasha Alexandrdef319f2009-06-16 16:00:15 -040018585/* pcm configuration: identical with ALC880 */
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018586#define alc662_pcm_analog_playback alc880_pcm_analog_playback
18587#define alc662_pcm_analog_capture alc880_pcm_analog_capture
18588#define alc662_pcm_digital_playback alc880_pcm_digital_playback
18589#define alc662_pcm_digital_capture alc880_pcm_digital_capture
18590
18591/*
18592 * configuration and preset
18593 */
18594static const char *alc662_models[ALC662_MODEL_LAST] = {
18595 [ALC662_3ST_2ch_DIG] = "3stack-dig",
18596 [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig",
18597 [ALC662_3ST_6ch] = "3stack-6ch",
18598 [ALC662_5ST_DIG] = "6stack-dig",
18599 [ALC662_LENOVO_101E] = "lenovo-101e",
Takashi Iwaib995d762007-10-17 10:41:06 +020018600 [ALC662_ASUS_EEEPC_P701] = "eeepc-p701",
Kailang Yang8c427222008-01-10 13:03:59 +010018601 [ALC662_ASUS_EEEPC_EP20] = "eeepc-ep20",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018602 [ALC662_ECS] = "ecs",
Kailang Yang6dda9f42008-05-27 12:05:31 +020018603 [ALC663_ASUS_M51VA] = "m51va",
18604 [ALC663_ASUS_G71V] = "g71v",
18605 [ALC663_ASUS_H13] = "h13",
18606 [ALC663_ASUS_G50V] = "g50v",
Kailang Yangf1d4e282008-08-26 14:03:29 +020018607 [ALC663_ASUS_MODE1] = "asus-mode1",
18608 [ALC662_ASUS_MODE2] = "asus-mode2",
18609 [ALC663_ASUS_MODE3] = "asus-mode3",
18610 [ALC663_ASUS_MODE4] = "asus-mode4",
18611 [ALC663_ASUS_MODE5] = "asus-mode5",
18612 [ALC663_ASUS_MODE6] = "asus-mode6",
Kailang Yangebb83ee2009-12-17 12:23:00 +010018613 [ALC663_ASUS_MODE7] = "asus-mode7",
18614 [ALC663_ASUS_MODE8] = "asus-mode8",
Takashi Iwai01f2bd42009-05-11 08:12:43 +020018615 [ALC272_DELL] = "dell",
18616 [ALC272_DELL_ZM1] = "dell-zm1",
Chris Pockelé9541ba12009-05-12 08:08:53 +020018617 [ALC272_SAMSUNG_NC10] = "samsung-nc10",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018618 [ALC662_AUTO] = "auto",
18619};
18620
18621static struct snd_pci_quirk alc662_cfg_tbl[] = {
Takashi Iwaidea0a502009-02-09 17:14:52 +010018622 SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_ECS),
Kailang Yang622e84c2009-04-21 07:39:04 +020018623 SND_PCI_QUIRK(0x1028, 0x02d6, "DELL", ALC272_DELL),
18624 SND_PCI_QUIRK(0x1028, 0x02f4, "DELL ZM1", ALC272_DELL_ZM1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018625 SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC663_ASUS_MODE1),
18626 SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC663_ASUS_MODE3),
Kailang Yangcec27c82010-02-04 14:18:18 +010018627 SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018628 SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC663_ASUS_MODE3),
18629 SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1),
18630 SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2),
18631 SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018632 SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1),
18633 SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018634 SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018635 SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7),
18636 SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7),
18637 SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8),
18638 SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3),
18639 SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018640 SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018641 SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2),
18642 SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018643 SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2),
18644 SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6),
18645 SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6),
18646 SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yangebb83ee2009-12-17 12:23:00 +010018647 SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018648 SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3),
18649 SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA),
18650 SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018651 SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_ASUS_MODE2),
18652 SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC663_ASUS_MODE5),
18653 SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC663_ASUS_MODE6),
18654 SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018655 SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018656 SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_ASUS_MODE2),
18657 SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_ASUS_MODE2),
Kailang Yang6dda9f42008-05-27 12:05:31 +020018658 SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M51VA", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018659 /*SND_PCI_QUIRK(0x1043, 0x1878, "ASUS M50Vr", ALC663_ASUS_MODE1),*/
18660 SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC663_ASUS_MODE3),
18661 SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018662 SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC663_ASUS_MODE1),
Kailang Yangcec27c82010-02-04 14:18:18 +010018663 SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC663_ASUS_MODE1),
Kailang Yang622e84c2009-04-21 07:39:04 +020018664 SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC663_ASUS_MODE1),
18665 SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018666 SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC663_ASUS_MODE1),
18667 SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_ASUS_MODE2),
18668 SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018669 SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018670 SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC663_ASUS_MODE1),
18671 SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC663_ASUS_MODE3),
Kailang Yang622e84c2009-04-21 07:39:04 +020018672 SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC663_ASUS_MODE1),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018673 SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC663_ASUS_MODE1),
Kailang Yang80ffe862008-10-15 11:23:27 +020018674 SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS G50V", ALC663_ASUS_G50V),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018675 /*SND_PCI_QUIRK(0x1043, 0x19a3, "ASUS NB", ALC663_ASUS_MODE1),*/
18676 SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC663_ASUS_MODE1),
18677 SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_ASUS_MODE2),
Kailang Yang622e84c2009-04-21 07:39:04 +020018678 SND_PCI_QUIRK(0x1043, 0x19d3, "ASUS NB", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018679 SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC663_ASUS_MODE1),
18680 SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC663_ASUS_MODE4),
Herton Ronaldo Krzesinski3da23ca2008-03-14 12:52:59 +010018681 SND_PCI_QUIRK(0x1043, 0x8290, "ASUS P5GC-MX", ALC662_3ST_6ch_DIG),
Kailang Yang291702f2007-10-16 14:28:03 +020018682 SND_PCI_QUIRK(0x1043, 0x82a1, "ASUS Eeepc", ALC662_ASUS_EEEPC_P701),
Kailang Yang8c427222008-01-10 13:03:59 +010018683 SND_PCI_QUIRK(0x1043, 0x82d1, "ASUS Eeepc EP20", ALC662_ASUS_EEEPC_EP20),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018684 SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS),
Herton Ronaldo Krzesinski95fe5f22008-09-26 23:48:45 -030018685 SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K",
18686 ALC662_3ST_6ch_DIG),
Takashi Iwai4dee8ba2010-01-13 17:20:08 +010018687 SND_PCI_QUIRK(0x1179, 0xff6e, "Toshiba NB20x", ALC662_AUTO),
Chris Pockelé9541ba12009-05-12 08:08:53 +020018688 SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10),
Herton Ronaldo Krzesinskicb559742008-09-26 23:47:45 -030018689 SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L",
18690 ALC662_3ST_6ch_DIG),
Kailang Yang6227cdc2010-02-25 08:36:52 +010018691 SND_PCI_QUIRK(0x152d, 0x2304, "Quanta WH1", ALC663_ASUS_H13),
Vedran Miletic19c009a2008-09-29 20:29:25 +020018692 SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG),
Takashi Iwai5bd37292009-04-21 18:36:30 +020018693 SND_PCI_QUIRK(0x1631, 0xc10c, "PB RS65", ALC663_ASUS_M51VA),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018694 SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo", ALC662_LENOVO_101E),
Takashi Iwai238713d2008-10-05 10:57:39 +020018695 SND_PCI_QUIRK(0x1849, 0x3662, "ASROCK K10N78FullHD-hSLI R3.0",
Vedran Miletic19c009a2008-09-29 20:29:25 +020018696 ALC662_3ST_6ch_DIG),
Takashi Iwaidea0a502009-02-09 17:14:52 +010018697 SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x",
18698 ALC663_ASUS_H13),
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018699 {}
18700};
18701
18702static struct alc_config_preset alc662_presets[] = {
18703 [ALC662_3ST_2ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018704 .mixers = { alc662_3ST_2ch_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018705 .init_verbs = { alc662_init_verbs },
18706 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18707 .dac_nids = alc662_dac_nids,
18708 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018709 .dig_in_nid = ALC662_DIGIN_NID,
18710 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18711 .channel_mode = alc662_3ST_2ch_modes,
18712 .input_mux = &alc662_capture_source,
18713 },
18714 [ALC662_3ST_6ch_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018715 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018716 .init_verbs = { alc662_init_verbs },
18717 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18718 .dac_nids = alc662_dac_nids,
18719 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018720 .dig_in_nid = ALC662_DIGIN_NID,
18721 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18722 .channel_mode = alc662_3ST_6ch_modes,
18723 .need_dac_fix = 1,
18724 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018725 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018726 [ALC662_3ST_6ch] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018727 .mixers = { alc662_3ST_6ch_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018728 .init_verbs = { alc662_init_verbs },
18729 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18730 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018731 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18732 .channel_mode = alc662_3ST_6ch_modes,
18733 .need_dac_fix = 1,
18734 .input_mux = &alc662_capture_source,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020018735 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018736 [ALC662_5ST_DIG] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018737 .mixers = { alc662_base_mixer, alc662_chmode_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018738 .init_verbs = { alc662_init_verbs },
18739 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18740 .dac_nids = alc662_dac_nids,
18741 .dig_out_nid = ALC662_DIGOUT_NID,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018742 .dig_in_nid = ALC662_DIGIN_NID,
18743 .num_channel_mode = ARRAY_SIZE(alc662_5stack_modes),
18744 .channel_mode = alc662_5stack_modes,
18745 .input_mux = &alc662_capture_source,
18746 },
18747 [ALC662_LENOVO_101E] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018748 .mixers = { alc662_lenovo_101e_mixer },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018749 .init_verbs = { alc662_init_verbs, alc662_sue_init_verbs },
18750 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18751 .dac_nids = alc662_dac_nids,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020018752 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18753 .channel_mode = alc662_3ST_2ch_modes,
18754 .input_mux = &alc662_lenovo_101e_capture_source,
18755 .unsol_event = alc662_lenovo_101e_unsol_event,
18756 .init_hook = alc662_lenovo_101e_all_automute,
18757 },
Kailang Yang291702f2007-10-16 14:28:03 +020018758 [ALC662_ASUS_EEEPC_P701] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018759 .mixers = { alc662_eeepc_p701_mixer },
Kailang Yang291702f2007-10-16 14:28:03 +020018760 .init_verbs = { alc662_init_verbs,
18761 alc662_eeepc_sue_init_verbs },
18762 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18763 .dac_nids = alc662_dac_nids,
Kailang Yang291702f2007-10-16 14:28:03 +020018764 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18765 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang291702f2007-10-16 14:28:03 +020018766 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018767 .setup = alc662_eeepc_setup,
Kailang Yang291702f2007-10-16 14:28:03 +020018768 .init_hook = alc662_eeepc_inithook,
18769 },
Kailang Yang8c427222008-01-10 13:03:59 +010018770 [ALC662_ASUS_EEEPC_EP20] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018771 .mixers = { alc662_eeepc_ep20_mixer,
Kailang Yang8c427222008-01-10 13:03:59 +010018772 alc662_chmode_mixer },
18773 .init_verbs = { alc662_init_verbs,
18774 alc662_eeepc_ep20_sue_init_verbs },
18775 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18776 .dac_nids = alc662_dac_nids,
Kailang Yang8c427222008-01-10 13:03:59 +010018777 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18778 .channel_mode = alc662_3ST_6ch_modes,
18779 .input_mux = &alc662_lenovo_101e_capture_source,
Takashi Iwai42171c12009-05-08 14:11:43 +020018780 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018781 .setup = alc662_eeepc_ep20_setup,
Kailang Yang8c427222008-01-10 13:03:59 +010018782 .init_hook = alc662_eeepc_ep20_inithook,
18783 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018784 [ALC662_ECS] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018785 .mixers = { alc662_ecs_mixer },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018786 .init_verbs = { alc662_init_verbs,
18787 alc662_ecs_init_verbs },
18788 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18789 .dac_nids = alc662_dac_nids,
18790 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18791 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018792 .unsol_event = alc662_eeepc_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018793 .setup = alc662_eeepc_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018794 .init_hook = alc662_eeepc_inithook,
18795 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018796 [ALC663_ASUS_M51VA] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018797 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018798 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18799 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18800 .dac_nids = alc662_dac_nids,
18801 .dig_out_nid = ALC662_DIGOUT_NID,
18802 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18803 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018804 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018805 .setup = alc663_m51va_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018806 .init_hook = alc663_m51va_inithook,
18807 },
18808 [ALC663_ASUS_G71V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018809 .mixers = { alc663_g71v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018810 .init_verbs = { alc662_init_verbs, alc663_g71v_init_verbs },
18811 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18812 .dac_nids = alc662_dac_nids,
18813 .dig_out_nid = ALC662_DIGOUT_NID,
18814 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18815 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018816 .unsol_event = alc663_g71v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018817 .setup = alc663_g71v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018818 .init_hook = alc663_g71v_inithook,
18819 },
18820 [ALC663_ASUS_H13] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018821 .mixers = { alc663_m51va_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018822 .init_verbs = { alc662_init_verbs, alc663_m51va_init_verbs },
18823 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18824 .dac_nids = alc662_dac_nids,
18825 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18826 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018827 .unsol_event = alc663_m51va_unsol_event,
18828 .init_hook = alc663_m51va_inithook,
18829 },
18830 [ALC663_ASUS_G50V] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018831 .mixers = { alc663_g50v_mixer },
Kailang Yang6dda9f42008-05-27 12:05:31 +020018832 .init_verbs = { alc662_init_verbs, alc663_g50v_init_verbs },
18833 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18834 .dac_nids = alc662_dac_nids,
18835 .dig_out_nid = ALC662_DIGOUT_NID,
18836 .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes),
18837 .channel_mode = alc662_3ST_6ch_modes,
18838 .input_mux = &alc663_capture_source,
18839 .unsol_event = alc663_g50v_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018840 .setup = alc663_g50v_setup,
Kailang Yang6dda9f42008-05-27 12:05:31 +020018841 .init_hook = alc663_g50v_inithook,
18842 },
Kailang Yangf1d4e282008-08-26 14:03:29 +020018843 [ALC663_ASUS_MODE1] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018844 .mixers = { alc663_m51va_mixer },
18845 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018846 .init_verbs = { alc662_init_verbs,
18847 alc663_21jd_amic_init_verbs },
18848 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18849 .hp_nid = 0x03,
18850 .dac_nids = alc662_dac_nids,
18851 .dig_out_nid = ALC662_DIGOUT_NID,
18852 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18853 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018854 .unsol_event = alc663_mode1_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018855 .setup = alc663_mode1_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018856 .init_hook = alc663_mode1_inithook,
18857 },
18858 [ALC662_ASUS_MODE2] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018859 .mixers = { alc662_1bjd_mixer },
18860 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018861 .init_verbs = { alc662_init_verbs,
18862 alc662_1bjd_amic_init_verbs },
18863 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18864 .dac_nids = alc662_dac_nids,
18865 .dig_out_nid = ALC662_DIGOUT_NID,
18866 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18867 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018868 .unsol_event = alc662_mode2_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018869 .setup = alc662_mode2_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018870 .init_hook = alc662_mode2_inithook,
18871 },
18872 [ALC663_ASUS_MODE3] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018873 .mixers = { alc663_two_hp_m1_mixer },
18874 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018875 .init_verbs = { alc662_init_verbs,
18876 alc663_two_hp_amic_m1_init_verbs },
18877 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18878 .hp_nid = 0x03,
18879 .dac_nids = alc662_dac_nids,
18880 .dig_out_nid = ALC662_DIGOUT_NID,
18881 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18882 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018883 .unsol_event = alc663_mode3_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018884 .setup = alc663_mode3_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018885 .init_hook = alc663_mode3_inithook,
18886 },
18887 [ALC663_ASUS_MODE4] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018888 .mixers = { alc663_asus_21jd_clfe_mixer },
18889 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018890 .init_verbs = { alc662_init_verbs,
18891 alc663_21jd_amic_init_verbs},
18892 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18893 .hp_nid = 0x03,
18894 .dac_nids = alc662_dac_nids,
18895 .dig_out_nid = ALC662_DIGOUT_NID,
18896 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18897 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018898 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018899 .setup = alc663_mode4_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018900 .init_hook = alc663_mode4_inithook,
18901 },
18902 [ALC663_ASUS_MODE5] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018903 .mixers = { alc663_asus_15jd_clfe_mixer },
18904 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018905 .init_verbs = { alc662_init_verbs,
18906 alc663_15jd_amic_init_verbs },
18907 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18908 .hp_nid = 0x03,
18909 .dac_nids = alc662_dac_nids,
18910 .dig_out_nid = ALC662_DIGOUT_NID,
18911 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18912 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018913 .unsol_event = alc663_mode5_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018914 .setup = alc663_mode5_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018915 .init_hook = alc663_mode5_inithook,
18916 },
18917 [ALC663_ASUS_MODE6] = {
Takashi Iwaif9e336f2008-10-31 16:37:07 +010018918 .mixers = { alc663_two_hp_m2_mixer },
18919 .cap_mixer = alc662_auto_capture_mixer,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018920 .init_verbs = { alc662_init_verbs,
18921 alc663_two_hp_amic_m2_init_verbs },
18922 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18923 .hp_nid = 0x03,
18924 .dac_nids = alc662_dac_nids,
18925 .dig_out_nid = ALC662_DIGOUT_NID,
18926 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18927 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018928 .unsol_event = alc663_mode6_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018929 .setup = alc663_mode6_setup,
Kailang Yangf1d4e282008-08-26 14:03:29 +020018930 .init_hook = alc663_mode6_inithook,
18931 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010018932 [ALC663_ASUS_MODE7] = {
18933 .mixers = { alc663_mode7_mixer },
18934 .cap_mixer = alc662_auto_capture_mixer,
18935 .init_verbs = { alc662_init_verbs,
18936 alc663_mode7_init_verbs },
18937 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18938 .hp_nid = 0x03,
18939 .dac_nids = alc662_dac_nids,
18940 .dig_out_nid = ALC662_DIGOUT_NID,
18941 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18942 .channel_mode = alc662_3ST_2ch_modes,
18943 .unsol_event = alc663_mode7_unsol_event,
18944 .setup = alc663_mode7_setup,
18945 .init_hook = alc663_mode7_inithook,
18946 },
18947 [ALC663_ASUS_MODE8] = {
18948 .mixers = { alc663_mode8_mixer },
18949 .cap_mixer = alc662_auto_capture_mixer,
18950 .init_verbs = { alc662_init_verbs,
18951 alc663_mode8_init_verbs },
18952 .num_dacs = ARRAY_SIZE(alc662_dac_nids),
18953 .hp_nid = 0x03,
18954 .dac_nids = alc662_dac_nids,
18955 .dig_out_nid = ALC662_DIGOUT_NID,
18956 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18957 .channel_mode = alc662_3ST_2ch_modes,
18958 .unsol_event = alc663_mode8_unsol_event,
18959 .setup = alc663_mode8_setup,
18960 .init_hook = alc663_mode8_inithook,
18961 },
Kailang Yang622e84c2009-04-21 07:39:04 +020018962 [ALC272_DELL] = {
18963 .mixers = { alc663_m51va_mixer },
18964 .cap_mixer = alc272_auto_capture_mixer,
18965 .init_verbs = { alc662_init_verbs, alc272_dell_init_verbs },
18966 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18967 .dac_nids = alc662_dac_nids,
18968 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18969 .adc_nids = alc272_adc_nids,
18970 .num_adc_nids = ARRAY_SIZE(alc272_adc_nids),
18971 .capsrc_nids = alc272_capsrc_nids,
18972 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018973 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018974 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018975 .init_hook = alc663_m51va_inithook,
18976 },
18977 [ALC272_DELL_ZM1] = {
18978 .mixers = { alc663_m51va_mixer },
18979 .cap_mixer = alc662_auto_capture_mixer,
18980 .init_verbs = { alc662_init_verbs, alc272_dell_zm1_init_verbs },
18981 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18982 .dac_nids = alc662_dac_nids,
18983 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18984 .adc_nids = alc662_adc_nids,
Takashi Iwaib59bdf32009-08-11 09:47:30 +020018985 .num_adc_nids = 1,
Kailang Yang622e84c2009-04-21 07:39:04 +020018986 .capsrc_nids = alc662_capsrc_nids,
18987 .channel_mode = alc662_3ST_2ch_modes,
Kailang Yang622e84c2009-04-21 07:39:04 +020018988 .unsol_event = alc663_m51va_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020018989 .setup = alc663_m51va_setup,
Kailang Yang622e84c2009-04-21 07:39:04 +020018990 .init_hook = alc663_m51va_inithook,
18991 },
Chris Pockelé9541ba12009-05-12 08:08:53 +020018992 [ALC272_SAMSUNG_NC10] = {
18993 .mixers = { alc272_nc10_mixer },
18994 .init_verbs = { alc662_init_verbs,
18995 alc663_21jd_amic_init_verbs },
18996 .num_dacs = ARRAY_SIZE(alc272_dac_nids),
18997 .dac_nids = alc272_dac_nids,
18998 .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes),
18999 .channel_mode = alc662_3ST_2ch_modes,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019000 /*.input_mux = &alc272_nc10_capture_source,*/
Chris Pockelé9541ba12009-05-12 08:08:53 +020019001 .unsol_event = alc663_mode4_unsol_event,
Takashi Iwai4f5d17062009-08-11 18:17:46 +020019002 .setup = alc663_mode4_setup,
Chris Pockelé9541ba12009-05-12 08:08:53 +020019003 .init_hook = alc663_mode4_inithook,
19004 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019005};
19006
19007
19008/*
19009 * BIOS auto configuration
19010 */
19011
Takashi Iwai7085ec12009-10-02 09:03:58 +020019012/* convert from MIX nid to DAC */
19013static inline hda_nid_t alc662_mix_to_dac(hda_nid_t nid)
19014{
19015 if (nid == 0x0f)
19016 return 0x02;
19017 else if (nid >= 0x0c && nid <= 0x0e)
19018 return nid - 0x0c + 0x02;
David Henningssoncc1c4522010-11-24 14:17:47 +010019019 else if (nid == 0x26) /* ALC887-VD has this DAC too */
19020 return 0x25;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019021 else
19022 return 0;
19023}
19024
19025/* get MIX nid connected to the given pin targeted to DAC */
19026static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
19027 hda_nid_t dac)
19028{
David Henningssoncc1c4522010-11-24 14:17:47 +010019029 hda_nid_t mix[5];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019030 int i, num;
19031
19032 num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
19033 for (i = 0; i < num; i++) {
19034 if (alc662_mix_to_dac(mix[i]) == dac)
19035 return mix[i];
19036 }
19037 return 0;
19038}
19039
19040/* look for an empty DAC slot */
19041static hda_nid_t alc662_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
19042{
19043 struct alc_spec *spec = codec->spec;
19044 hda_nid_t srcs[5];
19045 int i, j, num;
19046
19047 num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
19048 if (num < 0)
19049 return 0;
19050 for (i = 0; i < num; i++) {
19051 hda_nid_t nid = alc662_mix_to_dac(srcs[i]);
19052 if (!nid)
19053 continue;
19054 for (j = 0; j < spec->multiout.num_dacs; j++)
19055 if (spec->multiout.dac_nids[j] == nid)
19056 break;
19057 if (j >= spec->multiout.num_dacs)
19058 return nid;
19059 }
19060 return 0;
19061}
19062
19063/* fill in the dac_nids table from the parsed pin configuration */
19064static int alc662_auto_fill_dac_nids(struct hda_codec *codec,
19065 const struct auto_pin_cfg *cfg)
19066{
19067 struct alc_spec *spec = codec->spec;
19068 int i;
19069 hda_nid_t dac;
19070
19071 spec->multiout.dac_nids = spec->private_dac_nids;
19072 for (i = 0; i < cfg->line_outs; i++) {
19073 dac = alc662_look_for_dac(codec, cfg->line_out_pins[i]);
19074 if (!dac)
19075 continue;
19076 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19077 }
19078 return 0;
19079}
19080
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019081static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019082 hda_nid_t nid, unsigned int chs)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019083{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019084 return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019085 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
19086}
19087
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019088static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019089 hda_nid_t nid, unsigned int chs)
19090{
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019091 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019092 HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT));
19093}
19094
19095#define alc662_add_stereo_vol(spec, pfx, nid) \
19096 alc662_add_vol_ctl(spec, pfx, nid, 3)
19097#define alc662_add_stereo_sw(spec, pfx, nid) \
19098 alc662_add_sw_ctl(spec, pfx, nid, 3)
19099
19100/* add playback controls from the parsed DAC table */
19101static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec,
19102 const struct auto_pin_cfg *cfg)
19103{
19104 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019105 static const char *chname[4] = {
19106 "Front", "Surround", NULL /*CLFE*/, "Side"
19107 };
Takashi Iwai7085ec12009-10-02 09:03:58 +020019108 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019109 int i, err;
19110
19111 for (i = 0; i < cfg->line_outs; i++) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019112 nid = spec->multiout.dac_nids[i];
19113 if (!nid)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019114 continue;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019115 mix = alc662_dac_to_mix(codec, cfg->line_out_pins[i], nid);
19116 if (!mix)
19117 continue;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019118 if (i == 2) {
19119 /* Center/LFE */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019120 err = alc662_add_vol_ctl(spec, "Center", nid, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019121 if (err < 0)
19122 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019123 err = alc662_add_vol_ctl(spec, "LFE", nid, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019124 if (err < 0)
19125 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019126 err = alc662_add_sw_ctl(spec, "Center", mix, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019127 if (err < 0)
19128 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019129 err = alc662_add_sw_ctl(spec, "LFE", mix, 2);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019130 if (err < 0)
19131 return err;
19132 } else {
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019133 const char *pfx;
19134 if (cfg->line_outs == 1 &&
19135 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019136 if (cfg->hp_outs)
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019137 pfx = "Speaker";
19138 else
19139 pfx = "PCM";
19140 } else
19141 pfx = chname[i];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019142 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019143 if (err < 0)
19144 return err;
Takashi Iwai0d884cb2009-08-25 16:14:35 +020019145 if (cfg->line_outs == 1 &&
19146 cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19147 pfx = "Speaker";
Takashi Iwai7085ec12009-10-02 09:03:58 +020019148 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019149 if (err < 0)
19150 return err;
19151 }
19152 }
19153 return 0;
19154}
19155
19156/* add playback controls for speaker and HP outputs */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019157/* return DAC nid if any new DAC is assigned */
19158static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019159 const char *pfx)
19160{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019161 struct alc_spec *spec = codec->spec;
19162 hda_nid_t nid, mix;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019163 int err;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019164
19165 if (!pin)
19166 return 0;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019167 nid = alc662_look_for_dac(codec, pin);
19168 if (!nid) {
Takashi Iwai7085ec12009-10-02 09:03:58 +020019169 /* the corresponding DAC is already occupied */
19170 if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
19171 return 0; /* no way */
19172 /* create a switch only */
Takashi Iwai0afe5f82009-10-02 09:20:00 +020019173 return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019174 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
19175 }
19176
19177 mix = alc662_dac_to_mix(codec, pin, nid);
19178 if (!mix)
19179 return 0;
19180 err = alc662_add_vol_ctl(spec, pfx, nid, 3);
19181 if (err < 0)
Takashi Iwai24fb9172008-09-02 14:48:20 +020019182 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019183 err = alc662_add_sw_ctl(spec, pfx, mix, 3);
19184 if (err < 0)
19185 return err;
19186 return nid;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019187}
19188
19189/* create playback/capture controls for input pins */
Takashi Iwai05f5f472009-08-25 13:10:18 +020019190#define alc662_auto_create_input_ctls \
Takashi Iwai4b7348a2009-10-14 18:25:23 +020019191 alc882_auto_create_input_ctls
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019192
19193static void alc662_auto_set_output_and_unmute(struct hda_codec *codec,
19194 hda_nid_t nid, int pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019195 hda_nid_t dac)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019196{
Takashi Iwai7085ec12009-10-02 09:03:58 +020019197 int i, num;
Takashi Iwaice503f32010-07-30 10:37:29 +020019198 hda_nid_t srcs[HDA_MAX_CONNECTIONS];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019199
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019200 alc_set_pin_output(codec, nid, pin_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019201 /* need the manual connection? */
Takashi Iwai7085ec12009-10-02 09:03:58 +020019202 num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
19203 if (num <= 1)
19204 return;
19205 for (i = 0; i < num; i++) {
19206 if (alc662_mix_to_dac(srcs[i]) != dac)
19207 continue;
19208 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
19209 return;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019210 }
19211}
19212
19213static void alc662_auto_init_multi_out(struct hda_codec *codec)
19214{
19215 struct alc_spec *spec = codec->spec;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019216 int pin_type = get_pin_type(spec->autocfg.line_out_type);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019217 int i;
19218
19219 for (i = 0; i <= HDA_SIDE; i++) {
19220 hda_nid_t nid = spec->autocfg.line_out_pins[i];
19221 if (nid)
Takashi Iwaibaba8ee2007-04-23 17:17:48 +020019222 alc662_auto_set_output_and_unmute(codec, nid, pin_type,
Takashi Iwai7085ec12009-10-02 09:03:58 +020019223 spec->multiout.dac_nids[i]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019224 }
19225}
19226
19227static void alc662_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];
Takashi Iwai7085ec12009-10-02 09:03:58 +020019233 if (pin)
19234 alc662_auto_set_output_and_unmute(codec, pin, PIN_HP,
19235 spec->multiout.hp_nid);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019236 pin = spec->autocfg.speaker_pins[0];
19237 if (pin)
Takashi Iwai7085ec12009-10-02 09:03:58 +020019238 alc662_auto_set_output_and_unmute(codec, pin, PIN_OUT,
19239 spec->multiout.extra_out_nid[0]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019240}
19241
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019242#define ALC662_PIN_CD_NID ALC880_PIN_CD_NID
19243
19244static void alc662_auto_init_analog_input(struct hda_codec *codec)
19245{
19246 struct alc_spec *spec = codec->spec;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019247 struct auto_pin_cfg *cfg = &spec->autocfg;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019248 int i;
19249
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019250 for (i = 0; i < cfg->num_inputs; i++) {
19251 hda_nid_t nid = cfg->inputs[i].pin;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019252 if (alc_is_input_pin(codec, nid)) {
Takashi Iwai30ea0982010-09-16 18:47:56 +020019253 alc_set_input_pin(codec, nid, cfg->inputs[i].type);
Takashi Iwai52ca15b2009-03-23 12:51:55 +010019254 if (nid != ALC662_PIN_CD_NID &&
Takashi Iwaie82c0252009-03-23 15:17:38 +010019255 (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019256 snd_hda_codec_write(codec, nid, 0,
19257 AC_VERB_SET_AMP_GAIN_MUTE,
19258 AMP_OUT_MUTE);
19259 }
19260 }
19261}
19262
Takashi Iwaif511b012008-08-15 16:46:42 +020019263#define alc662_auto_init_input_src alc882_auto_init_input_src
19264
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019265static int alc662_parse_auto_config(struct hda_codec *codec)
19266{
19267 struct alc_spec *spec = codec->spec;
19268 int err;
19269 static hda_nid_t alc662_ignore[] = { 0x1d, 0 };
19270
19271 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19272 alc662_ignore);
19273 if (err < 0)
19274 return err;
19275 if (!spec->autocfg.line_outs)
19276 return 0; /* can't find valid BIOS pin config */
19277
Takashi Iwai7085ec12009-10-02 09:03:58 +020019278 err = alc662_auto_fill_dac_nids(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019279 if (err < 0)
19280 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019281 err = alc662_auto_create_multi_out_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019282 if (err < 0)
19283 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019284 err = alc662_auto_create_extra_out(codec,
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019285 spec->autocfg.speaker_pins[0],
19286 "Speaker");
19287 if (err < 0)
19288 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019289 if (err)
19290 spec->multiout.extra_out_nid[0] = err;
19291 err = alc662_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019292 "Headphone");
19293 if (err < 0)
19294 return err;
Takashi Iwai7085ec12009-10-02 09:03:58 +020019295 if (err)
19296 spec->multiout.hp_nid = err;
Takashi Iwai05f5f472009-08-25 13:10:18 +020019297 err = alc662_auto_create_input_ctls(codec, &spec->autocfg);
Takashi Iwaif12ab1e2007-04-12 15:51:47 +020019298 if (err < 0)
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019299 return err;
19300
19301 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
19302
Takashi Iwai757899a2010-07-30 10:48:14 +020019303 alc_auto_parse_digital(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019304
Takashi Iwai603c4012008-07-30 15:01:44 +020019305 if (spec->kctls.list)
Takashi Iwaid88897e2008-10-31 15:01:37 +010019306 add_mixer(spec, spec->kctls.list);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019307
19308 spec->num_mux_defs = 1;
Herton Ronaldo Krzesinski61b9b9b2009-01-28 09:16:33 -020019309 spec->input_mux = &spec->private_imux[0];
Kailang Yangea1fb292008-08-26 12:58:38 +020019310
Kailang Yangcec27c82010-02-04 14:18:18 +010019311 add_verb(spec, alc662_init_verbs);
19312 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019313 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
Kailang Yangcec27c82010-02-04 14:18:18 +010019314 add_verb(spec, alc663_init_verbs);
19315
19316 if (codec->vendor_id == 0x10ec0272)
19317 add_verb(spec, alc272_init_verbs);
Takashi Iwaiee979a142008-09-02 15:42:20 +020019318
19319 err = alc_auto_add_mic_boost(codec);
19320 if (err < 0)
19321 return err;
19322
Kailang Yang6227cdc2010-02-25 08:36:52 +010019323 if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
19324 codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
19325 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0x21);
19326 else
19327 alc_ssid_check(codec, 0x15, 0x1b, 0x14, 0);
Takashi Iwai4a79ba32009-04-22 16:31:35 +020019328
Takashi Iwai8c872862007-06-19 12:11:16 +020019329 return 1;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019330}
19331
19332/* additional initialization for auto-configuration model */
19333static void alc662_auto_init(struct hda_codec *codec)
19334{
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019335 struct alc_spec *spec = codec->spec;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019336 alc662_auto_init_multi_out(codec);
19337 alc662_auto_init_hp_out(codec);
19338 alc662_auto_init_analog_input(codec);
Takashi Iwaif511b012008-08-15 16:46:42 +020019339 alc662_auto_init_input_src(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019340 alc_auto_init_digital(codec);
Takashi Iwaif6c7e542008-02-12 18:32:23 +010019341 if (spec->unsol_event)
Kailang Yang7fb0d782008-10-15 11:12:35 +020019342 alc_inithook(codec);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019343}
19344
Todd Broch6be79482010-12-07 16:51:05 -080019345static void alc272_fixup_mario(struct hda_codec *codec,
19346 const struct alc_fixup *fix, int pre_init) {
19347 if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
19348 (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
19349 (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
19350 (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
19351 (0 << AC_AMPCAP_MUTE_SHIFT)))
19352 printk(KERN_WARNING
19353 "hda_codec: failed to override amp caps for NID 0x2\n");
19354}
19355
David Henningsson6cb3b702010-09-09 08:51:44 +020019356enum {
Daniel T Chen2df03512010-10-10 22:39:28 -040019357 ALC662_FIXUP_ASPIRE,
David Henningsson6cb3b702010-09-09 08:51:44 +020019358 ALC662_FIXUP_IDEAPAD,
Todd Broch6be79482010-12-07 16:51:05 -080019359 ALC272_FIXUP_MARIO,
David Henningsson6cb3b702010-09-09 08:51:44 +020019360};
19361
19362static const struct alc_fixup alc662_fixups[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019363 [ALC662_FIXUP_ASPIRE] = {
19364 .pins = (const struct alc_pincfg[]) {
19365 { 0x15, 0x99130112 }, /* subwoofer */
19366 { }
19367 }
19368 },
David Henningsson6cb3b702010-09-09 08:51:44 +020019369 [ALC662_FIXUP_IDEAPAD] = {
19370 .pins = (const struct alc_pincfg[]) {
19371 { 0x17, 0x99130112 }, /* subwoofer */
19372 { }
19373 }
19374 },
Todd Broch6be79482010-12-07 16:51:05 -080019375 [ALC272_FIXUP_MARIO] = {
19376 .func = alc272_fixup_mario,
19377 }
David Henningsson6cb3b702010-09-09 08:51:44 +020019378};
19379
19380static struct snd_pci_quirk alc662_fixup_tbl[] = {
Daniel T Chen2df03512010-10-10 22:39:28 -040019381 SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
Daniel T Chena0e90ac2010-11-20 10:20:35 -050019382 SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
Valentine Sinitsynd4118582010-10-01 22:24:08 +060019383 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
David Henningsson6cb3b702010-09-09 08:51:44 +020019384 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
19385 {}
19386};
19387
Todd Broch6be79482010-12-07 16:51:05 -080019388static const struct alc_model_fixup alc662_fixup_models[] = {
19389 {.id = ALC272_FIXUP_MARIO, .name = "mario"},
19390 {}
19391};
David Henningsson6cb3b702010-09-09 08:51:44 +020019392
19393
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019394static int patch_alc662(struct hda_codec *codec)
19395{
19396 struct alc_spec *spec;
19397 int err, board_config;
Kailang Yang693194f2010-10-21 08:51:48 +020019398 int coef;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019399
19400 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19401 if (!spec)
19402 return -ENOMEM;
19403
19404 codec->spec = spec;
19405
Kailang Yangda00c242010-03-19 11:23:45 +010019406 alc_auto_parse_customize_define(codec);
19407
Takashi Iwai2c3bf9a2008-06-04 12:39:38 +020019408 alc_fix_pll_init(codec, 0x20, 0x04, 15);
19409
Kailang Yang693194f2010-10-21 08:51:48 +020019410 coef = alc_read_coef_idx(codec, 0);
19411 if (coef == 0x8020 || coef == 0x8011)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019412 alc_codec_rename(codec, "ALC661");
Kailang Yang693194f2010-10-21 08:51:48 +020019413 else if (coef & (1 << 14) &&
19414 codec->bus->pci->subsystem_vendor == 0x1025 &&
19415 spec->cdefine.platform_type == 1)
Kailang Yangc027ddc2010-03-19 11:33:06 +010019416 alc_codec_rename(codec, "ALC272X");
Kailang Yang693194f2010-10-21 08:51:48 +020019417 else if (coef == 0x4011)
19418 alc_codec_rename(codec, "ALC656");
Kailang Yang274693f2009-12-03 10:07:50 +010019419
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019420 board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST,
19421 alc662_models,
19422 alc662_cfg_tbl);
19423 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +020019424 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19425 codec->chip_name);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019426 board_config = ALC662_AUTO;
19427 }
19428
19429 if (board_config == ALC662_AUTO) {
David Henningsson6cb3b702010-09-09 08:51:44 +020019430 alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019431 /* automatic parse from the BIOS config */
19432 err = alc662_parse_auto_config(codec);
19433 if (err < 0) {
19434 alc_free(codec);
19435 return err;
Takashi Iwai8c872862007-06-19 12:11:16 +020019436 } else if (!err) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019437 printk(KERN_INFO
19438 "hda_codec: Cannot set up configuration "
19439 "from BIOS. Using base mode...\n");
19440 board_config = ALC662_3ST_2ch_DIG;
19441 }
19442 }
19443
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019444 if (has_cdefine_beep(codec)) {
Takashi Iwai8af25912010-07-28 17:37:16 +020019445 err = snd_hda_attach_beep_device(codec, 0x1);
19446 if (err < 0) {
19447 alc_free(codec);
19448 return err;
19449 }
Kusanagi Kouichi680cd532009-02-05 00:00:58 +090019450 }
19451
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019452 if (board_config != ALC662_AUTO)
Takashi Iwaie9c364c2009-08-11 17:16:13 +020019453 setup_preset(codec, &alc662_presets[board_config]);
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019454
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019455 spec->stream_analog_playback = &alc662_pcm_analog_playback;
19456 spec->stream_analog_capture = &alc662_pcm_analog_capture;
19457
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019458 spec->stream_digital_playback = &alc662_pcm_digital_playback;
19459 spec->stream_digital_capture = &alc662_pcm_digital_capture;
19460
Takashi Iwaidd704692009-08-11 08:45:11 +020019461 if (!spec->adc_nids) {
19462 spec->adc_nids = alc662_adc_nids;
19463 spec->num_adc_nids = ARRAY_SIZE(alc662_adc_nids);
19464 }
19465 if (!spec->capsrc_nids)
19466 spec->capsrc_nids = alc662_capsrc_nids;
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019467
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019468 if (!spec->cap_mixer)
Takashi Iwaib59bdf32009-08-11 09:47:30 +020019469 set_capture_mixer(codec);
Takashi Iwaif9e336f2008-10-31 16:37:07 +010019470
Takashi Iwaidc1eae22010-07-29 15:30:02 +020019471 if (has_cdefine_beep(codec)) {
Kailang Yangda00c242010-03-19 11:23:45 +010019472 switch (codec->vendor_id) {
19473 case 0x10ec0662:
19474 set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
19475 break;
19476 case 0x10ec0272:
19477 case 0x10ec0663:
19478 case 0x10ec0665:
19479 set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
19480 break;
19481 case 0x10ec0273:
19482 set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
19483 break;
19484 }
Kailang Yangcec27c82010-02-04 14:18:18 +010019485 }
Takashi Iwai2134ea42008-01-10 16:53:55 +010019486 spec->vmaster_nid = 0x02;
19487
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019488 codec->patch_ops = alc_patch_ops;
David Henningsson6cb3b702010-09-09 08:51:44 +020019489 if (board_config == ALC662_AUTO) {
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019490 spec->init_hook = alc662_auto_init;
Todd Broch6be79482010-12-07 16:51:05 -080019491 alc_pick_fixup_model(codec, alc662_fixup_models,
19492 alc662_fixup_tbl, alc662_fixups, 0);
David Henningsson6cb3b702010-09-09 08:51:44 +020019493 }
19494
Kailang Yangbf1b0222010-10-21 08:49:56 +020019495 alc_init_jacks(codec);
19496
Takashi Iwaicb53c622007-08-10 17:21:45 +020019497#ifdef CONFIG_SND_HDA_POWER_SAVE
19498 if (!spec->loopback.amplist)
19499 spec->loopback.amplist = alc662_loopbacks;
19500#endif
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019501
19502 return 0;
19503}
19504
Kailang Yang274693f2009-12-03 10:07:50 +010019505static int patch_alc888(struct hda_codec *codec)
19506{
19507 if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
19508 kfree(codec->chip_name);
Kailang Yang01e0f132010-11-22 10:59:36 +010019509 if (codec->vendor_id == 0x10ec0887)
19510 codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
19511 else
19512 codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019513 if (!codec->chip_name) {
19514 alc_free(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019515 return -ENOMEM;
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019516 }
19517 return patch_alc662(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019518 }
Takashi Iwaiac2c92e2009-12-03 10:14:10 +010019519 return patch_alc882(codec);
Kailang Yang274693f2009-12-03 10:07:50 +010019520}
19521
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019522/*
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019523 * ALC680 support
19524 */
Kailang Yangc69aefa2010-08-17 10:39:22 +020019525#define ALC680_DIGIN_NID ALC880_DIGIN_NID
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019526#define ALC680_DIGOUT_NID ALC880_DIGOUT_NID
19527#define alc680_modes alc260_modes
19528
19529static hda_nid_t alc680_dac_nids[3] = {
19530 /* Lout1, Lout2, hp */
19531 0x02, 0x03, 0x04
19532};
19533
19534static hda_nid_t alc680_adc_nids[3] = {
19535 /* ADC0-2 */
19536 /* DMIC, MIC, Line-in*/
19537 0x07, 0x08, 0x09
19538};
19539
Kailang Yangc69aefa2010-08-17 10:39:22 +020019540/*
19541 * Analog capture ADC cgange
19542 */
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019543static void alc680_rec_autoswitch(struct hda_codec *codec)
19544{
19545 struct alc_spec *spec = codec->spec;
19546 struct auto_pin_cfg *cfg = &spec->autocfg;
19547 int pin_found = 0;
19548 int type_found = AUTO_PIN_LAST;
19549 hda_nid_t nid;
19550 int i;
19551
19552 for (i = 0; i < cfg->num_inputs; i++) {
19553 nid = cfg->inputs[i].pin;
19554 if (!(snd_hda_query_pin_caps(codec, nid) &
19555 AC_PINCAP_PRES_DETECT))
19556 continue;
19557 if (snd_hda_jack_detect(codec, nid)) {
19558 if (cfg->inputs[i].type < type_found) {
19559 type_found = cfg->inputs[i].type;
19560 pin_found = nid;
19561 }
19562 }
19563 }
19564
19565 nid = 0x07;
19566 if (pin_found)
19567 snd_hda_get_connections(codec, pin_found, &nid, 1);
19568
19569 if (nid != spec->cur_adc)
19570 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
19571 spec->cur_adc = nid;
19572 snd_hda_codec_setup_stream(codec, nid, spec->cur_adc_stream_tag, 0,
19573 spec->cur_adc_format);
19574}
19575
Kailang Yangc69aefa2010-08-17 10:39:22 +020019576static int alc680_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
19577 struct hda_codec *codec,
19578 unsigned int stream_tag,
19579 unsigned int format,
19580 struct snd_pcm_substream *substream)
19581{
19582 struct alc_spec *spec = codec->spec;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019583
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019584 spec->cur_adc = 0x07;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019585 spec->cur_adc_stream_tag = stream_tag;
19586 spec->cur_adc_format = format;
19587
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019588 alc680_rec_autoswitch(codec);
Kailang Yangc69aefa2010-08-17 10:39:22 +020019589 return 0;
19590}
19591
19592static int alc680_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
19593 struct hda_codec *codec,
19594 struct snd_pcm_substream *substream)
19595{
19596 snd_hda_codec_cleanup_stream(codec, 0x07);
19597 snd_hda_codec_cleanup_stream(codec, 0x08);
19598 snd_hda_codec_cleanup_stream(codec, 0x09);
19599 return 0;
19600}
19601
19602static struct hda_pcm_stream alc680_pcm_analog_auto_capture = {
19603 .substreams = 1, /* can be overridden */
19604 .channels_min = 2,
19605 .channels_max = 2,
19606 /* NID is set in alc_build_pcms */
19607 .ops = {
19608 .prepare = alc680_capture_pcm_prepare,
19609 .cleanup = alc680_capture_pcm_cleanup
19610 },
19611};
19612
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019613static struct snd_kcontrol_new alc680_base_mixer[] = {
19614 /* output mixer control */
19615 HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
19616 HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
19617 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x4, 0x0, HDA_OUTPUT),
19618 HDA_CODEC_MUTE("Headphone Playback Switch", 0x16, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +010019619 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x12, 0, HDA_INPUT),
19620 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0, HDA_INPUT),
19621 HDA_CODEC_VOLUME("Line In Boost Volume", 0x19, 0, HDA_INPUT),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019622 { }
19623};
19624
Kailang Yangc69aefa2010-08-17 10:39:22 +020019625static struct hda_bind_ctls alc680_bind_cap_vol = {
19626 .ops = &snd_hda_bind_vol,
19627 .values = {
19628 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19629 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19630 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19631 0
19632 },
19633};
19634
19635static struct hda_bind_ctls alc680_bind_cap_switch = {
19636 .ops = &snd_hda_bind_sw,
19637 .values = {
19638 HDA_COMPOSE_AMP_VAL(0x07, 3, 0, HDA_INPUT),
19639 HDA_COMPOSE_AMP_VAL(0x08, 3, 0, HDA_INPUT),
19640 HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT),
19641 0
19642 },
19643};
19644
19645static struct snd_kcontrol_new alc680_master_capture_mixer[] = {
19646 HDA_BIND_VOL("Capture Volume", &alc680_bind_cap_vol),
19647 HDA_BIND_SW("Capture Switch", &alc680_bind_cap_switch),
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019648 { } /* end */
19649};
19650
19651/*
19652 * generic initialization of ADC, input mixers and output mixers
19653 */
19654static struct hda_verb alc680_init_verbs[] = {
Kailang Yangc69aefa2010-08-17 10:39:22 +020019655 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19656 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
19657 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019658
Kailang Yangc69aefa2010-08-17 10:39:22 +020019659 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
19660 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19661 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
19662 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
19663 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
19664 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019665
19666 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19667 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19668 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19669 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
19670 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019671
19672 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
19673 {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019674 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN},
Kailang Yangc69aefa2010-08-17 10:39:22 +020019675
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019676 { }
19677};
19678
Kailang Yangc69aefa2010-08-17 10:39:22 +020019679/* toggle speaker-output according to the hp-jack state */
19680static void alc680_base_setup(struct hda_codec *codec)
19681{
19682 struct alc_spec *spec = codec->spec;
19683
19684 spec->autocfg.hp_pins[0] = 0x16;
19685 spec->autocfg.speaker_pins[0] = 0x14;
19686 spec->autocfg.speaker_pins[1] = 0x15;
Takashi Iwai66ceeb62010-08-30 13:05:52 +020019687 spec->autocfg.num_inputs = 2;
19688 spec->autocfg.inputs[0].pin = 0x18;
19689 spec->autocfg.inputs[0].type = AUTO_PIN_MIC;
19690 spec->autocfg.inputs[1].pin = 0x19;
Takashi Iwai86e29592010-09-09 14:50:17 +020019691 spec->autocfg.inputs[1].type = AUTO_PIN_LINE_IN;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019692}
19693
19694static void alc680_unsol_event(struct hda_codec *codec,
19695 unsigned int res)
19696{
19697 if ((res >> 26) == ALC880_HP_EVENT)
19698 alc_automute_amp(codec);
19699 if ((res >> 26) == ALC880_MIC_EVENT)
19700 alc680_rec_autoswitch(codec);
19701}
19702
19703static void alc680_inithook(struct hda_codec *codec)
19704{
19705 alc_automute_amp(codec);
19706 alc680_rec_autoswitch(codec);
19707}
19708
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019709/* create input playback/capture controls for the given pin */
19710static int alc680_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
19711 const char *ctlname, int idx)
19712{
19713 hda_nid_t dac;
19714 int err;
19715
19716 switch (nid) {
19717 case 0x14:
19718 dac = 0x02;
19719 break;
19720 case 0x15:
19721 dac = 0x03;
19722 break;
19723 case 0x16:
19724 dac = 0x04;
19725 break;
19726 default:
19727 return 0;
19728 }
19729 if (spec->multiout.dac_nids[0] != dac &&
19730 spec->multiout.dac_nids[1] != dac) {
19731 err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname,
19732 HDA_COMPOSE_AMP_VAL(dac, 3, idx,
19733 HDA_OUTPUT));
19734 if (err < 0)
19735 return err;
19736
19737 err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname,
19738 HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
19739
19740 if (err < 0)
19741 return err;
19742 spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac;
19743 }
19744
19745 return 0;
19746}
19747
19748/* add playback controls from the parsed DAC table */
19749static int alc680_auto_create_multi_out_ctls(struct alc_spec *spec,
19750 const struct auto_pin_cfg *cfg)
19751{
19752 hda_nid_t nid;
19753 int err;
19754
19755 spec->multiout.dac_nids = spec->private_dac_nids;
19756
19757 nid = cfg->line_out_pins[0];
19758 if (nid) {
19759 const char *name;
19760 if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
19761 name = "Speaker";
19762 else
19763 name = "Front";
19764 err = alc680_new_analog_output(spec, nid, name, 0);
19765 if (err < 0)
19766 return err;
19767 }
19768
19769 nid = cfg->speaker_pins[0];
19770 if (nid) {
19771 err = alc680_new_analog_output(spec, nid, "Speaker", 0);
19772 if (err < 0)
19773 return err;
19774 }
19775 nid = cfg->hp_pins[0];
19776 if (nid) {
19777 err = alc680_new_analog_output(spec, nid, "Headphone", 0);
19778 if (err < 0)
19779 return err;
19780 }
19781
19782 return 0;
19783}
19784
19785static void alc680_auto_set_output_and_unmute(struct hda_codec *codec,
19786 hda_nid_t nid, int pin_type)
19787{
19788 alc_set_pin_output(codec, nid, pin_type);
19789}
19790
19791static void alc680_auto_init_multi_out(struct hda_codec *codec)
19792{
19793 struct alc_spec *spec = codec->spec;
19794 hda_nid_t nid = spec->autocfg.line_out_pins[0];
19795 if (nid) {
19796 int pin_type = get_pin_type(spec->autocfg.line_out_type);
19797 alc680_auto_set_output_and_unmute(codec, nid, pin_type);
19798 }
19799}
19800
19801static void alc680_auto_init_hp_out(struct hda_codec *codec)
19802{
19803 struct alc_spec *spec = codec->spec;
19804 hda_nid_t pin;
19805
19806 pin = spec->autocfg.hp_pins[0];
19807 if (pin)
19808 alc680_auto_set_output_and_unmute(codec, pin, PIN_HP);
19809 pin = spec->autocfg.speaker_pins[0];
19810 if (pin)
19811 alc680_auto_set_output_and_unmute(codec, pin, PIN_OUT);
19812}
19813
19814/* pcm configuration: identical with ALC880 */
19815#define alc680_pcm_analog_playback alc880_pcm_analog_playback
19816#define alc680_pcm_analog_capture alc880_pcm_analog_capture
19817#define alc680_pcm_analog_alt_capture alc880_pcm_analog_alt_capture
19818#define alc680_pcm_digital_playback alc880_pcm_digital_playback
Kailang Yangc69aefa2010-08-17 10:39:22 +020019819#define alc680_pcm_digital_capture alc880_pcm_digital_capture
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019820
19821/*
19822 * BIOS auto configuration
19823 */
19824static int alc680_parse_auto_config(struct hda_codec *codec)
19825{
19826 struct alc_spec *spec = codec->spec;
19827 int err;
19828 static hda_nid_t alc680_ignore[] = { 0 };
19829
19830 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
19831 alc680_ignore);
19832 if (err < 0)
19833 return err;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019834
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019835 if (!spec->autocfg.line_outs) {
19836 if (spec->autocfg.dig_outs || spec->autocfg.dig_in_pin) {
19837 spec->multiout.max_channels = 2;
19838 spec->no_analog = 1;
19839 goto dig_only;
19840 }
19841 return 0; /* can't find valid BIOS pin config */
19842 }
19843 err = alc680_auto_create_multi_out_ctls(spec, &spec->autocfg);
19844 if (err < 0)
19845 return err;
19846
19847 spec->multiout.max_channels = 2;
19848
19849 dig_only:
19850 /* digital only support output */
Takashi Iwai757899a2010-07-30 10:48:14 +020019851 alc_auto_parse_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019852 if (spec->kctls.list)
19853 add_mixer(spec, spec->kctls.list);
19854
19855 add_verb(spec, alc680_init_verbs);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019856
19857 err = alc_auto_add_mic_boost(codec);
19858 if (err < 0)
19859 return err;
19860
19861 return 1;
19862}
19863
19864#define alc680_auto_init_analog_input alc882_auto_init_analog_input
19865
19866/* init callback for auto-configuration model -- overriding the default init */
19867static void alc680_auto_init(struct hda_codec *codec)
19868{
19869 struct alc_spec *spec = codec->spec;
19870 alc680_auto_init_multi_out(codec);
19871 alc680_auto_init_hp_out(codec);
19872 alc680_auto_init_analog_input(codec);
Takashi Iwai757899a2010-07-30 10:48:14 +020019873 alc_auto_init_digital(codec);
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019874 if (spec->unsol_event)
19875 alc_inithook(codec);
19876}
19877
19878/*
19879 * configuration and preset
19880 */
19881static const char *alc680_models[ALC680_MODEL_LAST] = {
Takashi Iwaid4a86d82010-06-23 17:51:26 +020019882 [ALC680_BASE] = "base",
19883 [ALC680_AUTO] = "auto",
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019884};
19885
19886static struct snd_pci_quirk alc680_cfg_tbl[] = {
19887 SND_PCI_QUIRK(0x1043, 0x12f3, "ASUS NX90", ALC680_BASE),
19888 {}
19889};
19890
19891static struct alc_config_preset alc680_presets[] = {
19892 [ALC680_BASE] = {
19893 .mixers = { alc680_base_mixer },
Kailang Yangc69aefa2010-08-17 10:39:22 +020019894 .cap_mixer = alc680_master_capture_mixer,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019895 .init_verbs = { alc680_init_verbs },
19896 .num_dacs = ARRAY_SIZE(alc680_dac_nids),
19897 .dac_nids = alc680_dac_nids,
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019898 .dig_out_nid = ALC680_DIGOUT_NID,
19899 .num_channel_mode = ARRAY_SIZE(alc680_modes),
19900 .channel_mode = alc680_modes,
Kailang Yangc69aefa2010-08-17 10:39:22 +020019901 .unsol_event = alc680_unsol_event,
19902 .setup = alc680_base_setup,
19903 .init_hook = alc680_inithook,
19904
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019905 },
19906};
19907
19908static int patch_alc680(struct hda_codec *codec)
19909{
19910 struct alc_spec *spec;
19911 int board_config;
19912 int err;
19913
19914 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
19915 if (spec == NULL)
19916 return -ENOMEM;
19917
19918 codec->spec = spec;
19919
19920 board_config = snd_hda_check_board_config(codec, ALC680_MODEL_LAST,
19921 alc680_models,
19922 alc680_cfg_tbl);
19923
19924 if (board_config < 0 || board_config >= ALC680_MODEL_LAST) {
19925 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
19926 codec->chip_name);
19927 board_config = ALC680_AUTO;
19928 }
19929
19930 if (board_config == ALC680_AUTO) {
19931 /* automatic parse from the BIOS config */
19932 err = alc680_parse_auto_config(codec);
19933 if (err < 0) {
19934 alc_free(codec);
19935 return err;
19936 } else if (!err) {
19937 printk(KERN_INFO
19938 "hda_codec: Cannot set up configuration "
19939 "from BIOS. Using base mode...\n");
19940 board_config = ALC680_BASE;
19941 }
19942 }
19943
19944 if (board_config != ALC680_AUTO)
19945 setup_preset(codec, &alc680_presets[board_config]);
19946
19947 spec->stream_analog_playback = &alc680_pcm_analog_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019948 spec->stream_analog_capture = &alc680_pcm_analog_auto_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019949 spec->stream_digital_playback = &alc680_pcm_digital_playback;
Kailang Yangc69aefa2010-08-17 10:39:22 +020019950 spec->stream_digital_capture = &alc680_pcm_digital_capture;
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019951
19952 if (!spec->adc_nids) {
19953 spec->adc_nids = alc680_adc_nids;
19954 spec->num_adc_nids = ARRAY_SIZE(alc680_adc_nids);
19955 }
19956
19957 if (!spec->cap_mixer)
19958 set_capture_mixer(codec);
19959
19960 spec->vmaster_nid = 0x02;
19961
19962 codec->patch_ops = alc_patch_ops;
19963 if (board_config == ALC680_AUTO)
19964 spec->init_hook = alc680_auto_init;
19965
19966 return 0;
19967}
19968
19969/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070019970 * patch entries
19971 */
Takashi Iwai1289e9e2008-11-27 15:47:11 +010019972static struct hda_codec_preset snd_hda_preset_realtek[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070019973 { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
Kailang Yangdf694da2005-12-05 19:42:22 +010019974 { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019975 { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
Kailang Yanga361d842007-06-05 12:30:55 +020019976 { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
Kailang Yangf6a92242007-12-13 16:52:54 +010019977 { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019978 { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
Kailang Yang01afd412008-10-15 11:22:09 +020019979 { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
Kailang Yangebb83ee2009-12-17 12:23:00 +010019980 { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019981 { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019982 .patch = patch_alc861 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019983 { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
19984 { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
19985 { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019986 { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
Takashi Iwai49535502009-06-30 15:28:30 +020019987 .patch = patch_alc882 },
Kailang Yangbc9f98a2007-04-12 13:06:07 +020019988 { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
19989 .patch = patch_alc662 },
Kailang Yang6dda9f42008-05-27 12:05:31 +020019990 { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
Kailang Yangcec27c82010-02-04 14:18:18 +010019991 { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
Kailang Yang6227cdc2010-02-25 08:36:52 +010019992 { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
Kailang Yangd1eb57f2010-06-23 16:25:26 +020019993 { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
Jakub Schmidtkef32610e2007-02-02 18:17:27 +010019994 { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070019995 { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
Takashi Iwai49535502009-06-30 15:28:30 +020019996 { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
Clive Messer669faba2008-09-30 15:49:13 +020019997 { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020019998 .patch = patch_alc882 },
Takashi Iwaicb308f92008-04-16 14:13:29 +020019999 { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
Takashi Iwai49535502009-06-30 15:28:30 +020020000 .patch = patch_alc882 },
Kailang Yangdf694da2005-12-05 19:42:22 +010020001 { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
Kailang Yang01e0f132010-11-22 10:59:36 +010020002 { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
Kailang Yang44426082008-10-15 11:18:05 +020020003 { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
Takashi Iwai49535502009-06-30 15:28:30 +020020004 .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020005 { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },
Takashi Iwai49535502009-06-30 15:28:30 +020020006 { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
Kailang Yang274693f2009-12-03 10:07:50 +010020007 { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070020008 {} /* terminator */
20009};
Takashi Iwai1289e9e2008-11-27 15:47:11 +010020010
20011MODULE_ALIAS("snd-hda-codec-id:10ec*");
20012
20013MODULE_LICENSE("GPL");
20014MODULE_DESCRIPTION("Realtek HD-audio codec");
20015
20016static struct hda_codec_preset_list realtek_list = {
20017 .preset = snd_hda_preset_realtek,
20018 .owner = THIS_MODULE,
20019};
20020
20021static int __init patch_realtek_init(void)
20022{
20023 return snd_hda_add_codec_preset(&realtek_list);
20024}
20025
20026static void __exit patch_realtek_exit(void)
20027{
20028 snd_hda_delete_codec_preset(&realtek_list);
20029}
20030
20031module_init(patch_realtek_init)
20032module_exit(patch_realtek_exit)